-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Application/build.gradle b/Application/build.gradle
deleted file mode 100644
index dd745bc..0000000
--- a/Application/build.gradle
+++ /dev/null
@@ -1,70 +0,0 @@
-
-buildscript {
- repositories {
- jcenter()
- maven {
- url 'https://maven.google.com/'
- name 'Google'
- }
- google()
- }
-
- dependencies {
- classpath 'com.android.tools.build:gradle:4.1.3'
- }
-}
-
-apply plugin: 'com.android.application'
-
-repositories {
- jcenter()
- maven {
- url 'https://maven.google.com/'
- name 'Google'
- }
-}
-
-dependencies {
- implementation "com.android.support:gridlayout-v7:28.0.0"
- implementation "com.android.support:cardview-v7:28.0.0"
- implementation "com.android.support:appcompat-v7:28.0.0"
- implementation 'com.android.support:support-v13:28.0.0'
- implementation 'com.android.support.constraint:constraint-layout:2.0.4'
- implementation project(':android_antlib_4-14')
-}
-
-
-// The sample build uses multiple directories to
-// keep boilerplate and common code separate from
-// the main sample code.
-List dirs = [
- 'main', // main sample code; look here for the interesting stuff.
- 'common', // components that are reused by multiple samples
- 'template'] // boilerplate code that is generated by the sample template process
-
-android {
- compileSdkVersion 28
-
- defaultConfig {
- minSdkVersion 16
- targetSdkVersion 28
- }
-
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_7
- targetCompatibility JavaVersion.VERSION_1_7
- }
-
- sourceSets {
- main {
- dirs.each { dir ->
- java.srcDirs "src/${dir}/java"
- res.srcDirs "src/${dir}/res"
- }
- }
- androidTest.setRoot('tests')
- androidTest.java.srcDirs = ['tests/src']
-
- }
-
-}
diff --git a/Application/src/main/AndroidManifest.xml b/Application/src/main/AndroidManifest.xml
deleted file mode 100644
index 33e4dda..0000000
--- a/Application/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Application/src/main/java/org/surfsite/iconsole/BluetoothChatFragment.java b/Application/src/main/java/org/surfsite/iconsole/BluetoothChatFragment.java
deleted file mode 100644
index fa43b09..0000000
--- a/Application/src/main/java/org/surfsite/iconsole/BluetoothChatFragment.java
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright (C) 2014 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 org.surfsite.iconsole;
-
-import android.annotation.SuppressLint;
-import android.app.ActionBar;
-import android.app.Activity;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.NumberPicker;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.lang.ref.WeakReference;
-
-/**
- * This fragment controls Bluetooth to communicate with other devices.
- */
-public class BluetoothChatFragment extends Fragment {
- static class MyInnerHandler extends Handler{
- WeakReference mFrag;
-
- MyInnerHandler(BluetoothChatFragment aFragment) {
- mFrag = new WeakReference(aFragment);
- }
-
- @Override
- public void handleMessage(Message msg) {
- BluetoothChatFragment theFrag = mFrag.get();
- if (theFrag == null) {
- return;
- }
- FragmentActivity activity = theFrag.getActivity();
-
- switch (msg.what) {
- case Constants.MESSAGE_STATE_CHANGE:
- switch (msg.arg1) {
- case BluetoothChatService.STATE_CONNECTED:
- theFrag.setStatus(theFrag.getString(R.string.title_connected_to, theFrag.mConnectedDeviceName));
- //mConversationArrayAdapter.clear();
- theFrag.mStartButton.setEnabled(true);
- theFrag.mStopButton.setEnabled(true);
- theFrag.mDisconnectButton.setEnabled(true);
- theFrag.mLevel.setEnabled(true);
- theFrag.mLevel.setValue(1);
- break;
- case BluetoothChatService.STATE_CONNECTING:
- theFrag.setStatus(R.string.title_connecting);
- theFrag.mStartButton.setEnabled(false);
- theFrag.mStopButton.setEnabled(false);
- theFrag.mDisconnectButton.setEnabled(false);
- theFrag.mLevel.setEnabled(false);
- break;
- case BluetoothChatService.STATE_LISTEN:
- case BluetoothChatService.STATE_NONE:
- theFrag.setStatus(R.string.title_not_connected);
- theFrag.mStartButton.setEnabled(false);
- theFrag.mStopButton.setEnabled(false);
- theFrag.mDisconnectButton.setEnabled(false);
- theFrag.mLevel.setEnabled(false);
- break;
- }
- break;
- case Constants.MESSAGE_DATA:
- if (!(msg.obj instanceof IConsole.Data))
- return;
- IConsole.Data data = (IConsole.Data) msg.obj;
- theFrag.mChannelService.setSpeed(data.mSpeed10 / 10.0);
- theFrag.mChannelService.setPower(data.mPower10 / 10);
- theFrag.mChannelService.setCadence(data.mRPM);
-
- theFrag.mSpeedText.setText(String.format("% 3.1f", data.mSpeed10 / 10.0));
- theFrag.mPowerText.setText(String.format("% 3.1f", data.mPower10 / 10.0));
- theFrag.mRPMText.setText(String.format("%d", data.mRPM));
- theFrag.mDistanceText.setText(String.format("% 3.1f", data.mDistance10 / 10.0));
- theFrag.mCaloriesText.setText(String.format("% 3d", data.mCalories));
- theFrag.mHFText.setText(String.format("%d", data.mHF));
- theFrag.mTimeText.setText(String.format("%s", data.getTimeStr()));
- //mLevel.setValue(data.mLevel);
- break;
- case Constants.MESSAGE_WRITE:
- //byte[] writeBuf = (byte[]) msg.obj;
- // construct a string from the buffer
- //String writeMessage = new String(writeBuf);
- //mConversationArrayAdapter.add("Me: " + writeMessage);
- break;
- case Constants.MESSAGE_READ:
- //byte[] readBuf = (byte[]) msg.obj;
- // construct a string from the valid bytes in the buffer
- //String readMessage = new String(readBuf, 0, msg.arg1);
- //mConversationArrayAdapter.add(mConnectedDeviceName + ": " + readMessage);
- break;
- case Constants.MESSAGE_DEVICE_NAME:
- // save the connected device's name
- theFrag.mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
- if (null != activity) {
- Toast.makeText(activity, "Connected to "
- + theFrag.mConnectedDeviceName, Toast.LENGTH_SHORT).show();
- }
- break;
- case Constants.MESSAGE_TOAST:
- if (null != activity) {
- Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
- Toast.LENGTH_SHORT).show();
- }
- break;
- }
- }
- }
-
- private final Handler mHandler = new MyInnerHandler(this);
-
- private static final String TAG = "BluetoothChatFragment";
-
- // Intent request codes
- private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
- private static final int REQUEST_ENABLE_BT = 3;
-
- // Layout Views
- //private ListView mConversationView;
- private Button mStartButton;
- private Button mStopButton;
- private Button mDisconnectButton;
- private NumberPicker mLevel;
- private TextView mSpeedText;
- private TextView mPowerText;
- private TextView mRPMText;
- private TextView mDistanceText;
- private TextView mCaloriesText;
- private TextView mHFText;
- private TextView mTimeText;
- /**
- * Name of the connected device
- */
- private String mConnectedDeviceName = null;
-
- /**
- * Array adapter for the conversation thread
- private ArrayAdapter mConversationArrayAdapter;
- */
-
- /**
- * Local Bluetooth adapter
- */
- private BluetoothAdapter mBluetoothAdapter = null;
-
- /**
- * Member object for the chat services
- */
- private BluetoothChatService mChatService = null;
- private boolean mIsBound;
- private ChannelService.ChannelServiceComm mChannelService;
- /**
- * The Handler that gets information back from the BluetoothChatService
- */
- private boolean mChannelServiceBound = false;
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- // This is called when the connection with the service has been
- // established, giving us the service object we can use to
- // interact with the service. Because we have bound to a explicit
- // service that we know is running in our own process, we can
- // cast its IBinder to a concrete class and directly access it.
- mChatService = ((BluetoothChatService.BluetoothChatServiceI) service).getService();
- ((BluetoothChatService.BluetoothChatServiceI) service).setHandler(mHandler);
- Log.d(TAG, "onServiceConnected()");
- }
-
- public void onServiceDisconnected(ComponentName className) {
- // This is called when the connection with the service has been
- // unexpectedly disconnected -- that is, its process crashed.
- // Because it is running in our same process, we should never
- // see this happen.
- mChatService = null;
-
- }
- };
- private ServiceConnection mChannelServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder serviceBinder) {
- Log.v(TAG, "mChannelServiceConnection.onServiceConnected...");
-
- mChannelService = (ChannelService.ChannelServiceComm) serviceBinder;
-
-
- Log.v(TAG, "...mChannelServiceConnection.onServiceConnected");
- }
-
- @Override
- public void onServiceDisconnected(ComponentName arg0) {
- Log.v(TAG, "mChannelServiceConnection.onServiceDisconnected...");
-
- // Clearing and disabling when disconnecting from ChannelService
- mChannelService = null;
-
- Log.v(TAG, "...mChannelServiceConnection.onServiceDisconnected");
- }
- };
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
- // Get local Bluetooth adapter
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-
- // If the adapter is null, then Bluetooth is not supported
- if (mBluetoothAdapter == null) {
- FragmentActivity activity = getActivity();
- Toast.makeText(activity, "Bluetooth is not available", Toast.LENGTH_LONG).show();
- activity.finish();
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- // If BT is not on, request that it be enabled.
- // setupChat() will then be called during onActivityResult
- if (null == mBluetoothAdapter || !mBluetoothAdapter.isEnabled()) {
- Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
- startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
- // Otherwise, setup the chat session
- } else if (mChatService == null) {
- setupChat();
- }
- if (!mChannelServiceBound) doBindChannelService();
-
- }
-
- @Override
- public void onDestroy() {
- if (mChatService != null) {
- mChatService.stopBT();
- }
- Log.d(TAG, "onDestroy()");
- doUnbindService();
- doUnbindChannelService();
- mChannelServiceConnection = null;
-
- super.onDestroy();
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- // Performing this check in onResume() covers the case in which BT was
- // not enabled during onStart(), so we were paused to enable it...
- // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
- if (mChatService != null) {
- // Only if the state is STATE_NONE, do we know that we haven't started already
- if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
- // Start the Bluetooth chat services
- mChatService.startBT();
- }
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- return inflater.inflate(R.layout.fragment_bluetooth_chat, container, false);
- }
-
- @Override
- public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
- //mConversationView = (ListView) view.findViewById(R.id.in);
- mStartButton = (Button) view.findViewById(R.id.button_start);
- mStopButton = (Button) view.findViewById(R.id.button_stop);
- mDisconnectButton = (Button) view.findViewById(R.id.button_disconnect);
- mLevel = (NumberPicker) view.findViewById(R.id.Level);
- mLevel.setMaxValue(32);
- mLevel.setMinValue(1);
- mLevel.setValue(1);
- mLevel.setWrapSelectorWheel(false);
- mLevel.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
- mSpeedText = (TextView) view.findViewById(R.id.Speed);
- mPowerText = (TextView) view.findViewById(R.id.Power);
- mRPMText = (TextView) view.findViewById(R.id.RPM);
- mDistanceText = (TextView) view.findViewById(R.id.Distance);
- mCaloriesText = (TextView) view.findViewById(R.id.Calories);
- mHFText = (TextView) view.findViewById(R.id.Heart);
- mTimeText = (TextView) view.findViewById(R.id.Time);
- }
-
- void doBindService() {
- Log.d(TAG, "doBindService()");
-
- // Establish a connection with the service. We use an explicit
- // class name because we want a specific service implementation that
- // we know will be running in our own process (and thus won't be
- // supporting component replacement by other applications).
- getActivity().bindService(new Intent(getActivity(), BluetoothChatService.class), mConnection, Context.BIND_AUTO_CREATE);
- mIsBound = true;
- }
-
- void doUnbindService() {
- if (mIsBound) {
- // Detach our existing connection.
- getActivity().unbindService(mConnection);
- mIsBound = false;
- }
- }
-
- private void doBindChannelService() {
- Log.v(TAG, "doBindChannelService...");
-
- // Binds to ChannelService. ChannelService binds and manages connection between the
- // app and the ANT Radio Service
- mChannelServiceBound = getActivity().bindService(new Intent(getActivity(), ChannelService.class), mChannelServiceConnection, Context.BIND_AUTO_CREATE);
-
- if (!mChannelServiceBound) //If the bind returns false, run the unbind method to update the GUI
- doUnbindChannelService();
-
- Log.i(TAG, " Channel Service binding = " + mChannelServiceBound);
-
- Log.v(TAG, "...doBindChannelService");
- }
-
- private void doUnbindChannelService() {
- Log.v(TAG, "doUnbindChannelService...");
-
- if (mChannelServiceBound) {
- getActivity().unbindService(mChannelServiceConnection);
-
- mChannelServiceBound = false;
- }
-
- Log.v(TAG, "...doUnbindChannelService");
- }
-
- /**
- * Set up the UI and background operations for chat.
- */
- private void setupChat() {
- Log.d(TAG, "setupChat()");
-
- if (!mIsBound)
- doBindService();
-
- mStartButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mLevel.setValue(1);
- if (mChatService != null)
- mChatService.startIConsole();
- }
- });
-
- mStopButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mLevel.setValue(1);
- if (mChatService != null)
- mChatService.stopIConsole();
- }
- });
-
- mDisconnectButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mLevel.setValue(1);
- if (mChatService != null)
- mChatService.stopBT();
- }
- });
-
- mStartButton.setEnabled(false);
- mStopButton.setEnabled(false);
- mDisconnectButton.setEnabled(false);
- mLevel.setEnabled(false);
- mLevel.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
- @Override
- public void onValueChange(NumberPicker p, int oldval, int newval) {
- //Log.e(TAG, "setLevel");
- if (mChatService != null) {
- if (!mChatService.setLevel(newval))
- Log.e(TAG, "setLevel failed");
-
- }
- }
- });
- }
-
- /**
- * Makes this device discoverable for 300 seconds (5 minutes).
- */
- private void ensureDiscoverable() {
- if (mBluetoothAdapter.getScanMode() !=
- BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
- Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
- discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
- startActivity(discoverableIntent);
- }
- }
-
- /**
- * Sends a message.
- *
- * @param message A string of text to send.
- */
- private void sendMessage(String message) {
- if (mChatService == null)
- return;
-
- // Check that we're actually connected before trying anything
- if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
- Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
- return;
- }
-
- mChatService.startIConsole();
- }
-
- /**
- * Updates the status on the action bar.
- *
- * @param resId a string resource ID
- */
- private void setStatus(int resId) {
- FragmentActivity activity = getActivity();
- if (null == activity) {
- return;
- }
- final ActionBar actionBar = activity.getActionBar();
- if (null == actionBar) {
- return;
- }
- actionBar.setSubtitle(resId);
- }
-
- /**
- * Updates the status on the action bar.
- *
- * @param subTitle status
- */
- private void setStatus(CharSequence subTitle) {
- FragmentActivity activity = getActivity();
- if (null == activity) {
- return;
- }
- final ActionBar actionBar = activity.getActionBar();
- if (null == actionBar) {
- return;
- }
- actionBar.setSubtitle(subTitle);
- }
-
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case REQUEST_CONNECT_DEVICE_SECURE:
- // When DeviceListActivity returns with a device to connect
- if (resultCode == Activity.RESULT_OK) {
- connectDevice(data, true);
- }
- break;
- case REQUEST_ENABLE_BT:
- // When the request to enable Bluetooth returns
- if (resultCode == Activity.RESULT_OK) {
- // Bluetooth is now enabled, so set up a chat session
- setupChat();
- } else {
- // User did not enable Bluetooth or an error occurred
- Log.d(TAG, "BT not enabled");
- Toast.makeText(getActivity(), R.string.bt_not_enabled_leaving,
- Toast.LENGTH_SHORT).show();
- getActivity().finish();
- }
- }
- }
-
- /**
- * Establish connection with other device
- *
- * @param data An {@link Intent} with {@link DeviceListActivity#EXTRA_DEVICE_ADDRESS} extra.
- * @param secure Socket Security type - Secure (true) , Insecure (false)
- */
- private void connectDevice(Intent data, boolean secure) {
- // Get the device MAC address
- String address = data.getExtras()
- .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
- // Get the BluetoothDevice object
- BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
- // Attempt to connect to the device
- if (mChatService != null)
- mChatService.connect(device);
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- inflater.inflate(R.menu.bluetooth_chat, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.secure_connect_scan: {
- // Launch the DeviceListActivity to see devices and do scan
- Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
- startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
- return true;
- }
- }
- return false;
- }
-
-}
diff --git a/Application/src/main/java/org/surfsite/iconsole/BluetoothChatService.java b/Application/src/main/java/org/surfsite/iconsole/BluetoothChatService.java
deleted file mode 100644
index 0303cd3..0000000
--- a/Application/src/main/java/org/surfsite/iconsole/BluetoothChatService.java
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * Copyright (C) 2014 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 org.surfsite.iconsole;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothSocket;
-import android.content.Intent;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.UUID;
-
-/**
- * This class does all the work for setting up and managing Bluetooth
- * connections with other devices. It has a thread that listens for
- * incoming connections, a thread for connecting with a device, and a
- * thread for performing data transmissions when connected.
- */
-public class BluetoothChatService extends Service {
- // 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
- // Debugging
- private static final String TAG = "BluetoothChatService";
- // Name for the SDP record when creating server socket
- private static final String NAME_SECURE = "BluetoothChatSecure";
- private static final String NAME_INSECURE = "BluetoothChatInsecure";
- // Unique UUID for this application
- private static final UUID SERIAL_PORT_CLASS = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
- // Member fields
- private final BluetoothAdapter mAdapter;
- // This is the object that receives interactions from clients. See
- // RemoteService for a more complete example.
- private final IBinder mBinder = new BluetoothChatServiceI();
- private Handler mHandler;
- private ConnectThread mConnectThread;
- private ConnectedThread mConnectedThread;
- private int mState;
- private int mNewState;
- private NotificationManager mNM;
- private int NOTIFICATION = R.string.local_service_started;
-
-
- public BluetoothChatService() {
- super();
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- mState = STATE_NONE;
- mNewState = mState;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
-
- }
-
- boolean startIConsole() {
- return mConnectedThread.startIConsole();
- }
-
- boolean stopIConsole() {
- return mConnectedThread.stopIConsole();
- }
-
- boolean setLevel(int level) {
- return mConnectedThread.setLevel(level);
- }
-
- /**
- * Start the ConnectThread to initiate a connection to a remote device.
- *
- * @param device The BluetoothDevice to connect
- */
- public synchronized void connect(BluetoothDevice device) {
- Log.d(TAG, "connect to: " + device);
-
- // Cancel any thread attempting to make a connection
- if (mState == 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();
- // Update UI title
- updateUserInterfaceTitle();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- Log.i(TAG, "onBind");
-
- return mBinder;
- }
-
- /**
- * Update UI title according to the current state of the chat connection
- */
- private synchronized void updateUserInterfaceTitle() {
- mState = getState();
- Log.d(TAG, "updateUserInterfaceTitle() " + mNewState + " -> " + mState);
- mNewState = mState;
-
- // Give the new state to the Handler so the UI Activity can update
- if (mHandler != null)
- mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, mNewState, -1).sendToTarget();
- }
-
- /**
- * Return the current connection state.
- */
- public synchronized int getState() {
- return mState;
- }
-
- /**
- * Start the chat service. Specifically startBT AcceptThread to begin a
- * session in listening (server) mode. Called by the Activity onResume()
- */
- public int onStartCommand(Intent intent, int flags, int startId) {
- Log.i(TAG, "Received onStartCommand() id " + startId + ": " + intent);
- return START_NOT_STICKY;
- }
-
- @Override
- public void onDestroy() {
- stopBT();
-
- // Tell the user we stopped.
- Log.i(TAG, "onDestroy");
- super.onDestroy();
-
- }
-
- /**
- * Show a notification while this service is running.
- */
- private void showNotification() {
- // In this sample, we'll use the same text for the ticker and the expanded notification
- CharSequence text = getText(R.string.local_service_started);
- Intent myIntent = new Intent(this, MainActivity.class);
- myIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-
- // The PendingIntent to launch our activity if the user selects this notification
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0, myIntent, 0);
-
- // Set the info for the views that show in the notification panel.
- Notification notification = new Notification.Builder(this)
- .setSmallIcon(R.drawable.ic_action_device_access_bluetooth_searching) // the status icon
- .setTicker(text) // the status text
- .setWhen(System.currentTimeMillis()) // the time stamp
- .setContentTitle(getText(R.string.local_service_label)) // the label of the entry
- .setContentText(text) // the contents of the entry
- .setContentIntent(contentIntent) // The intent to send when the entry is clicked
- .build();
-
- // Send the notification.
- mNM.notify(NOTIFICATION, notification);
- }
-
- void startBT() {
- Log.d(TAG, "startBT");
-
- // 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;
- }
- // Update UI title
- updateUserInterfaceTitle();
- }
-
- /**
- * 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) {
- Log.d(TAG, "connected");
-
- // 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;
- }
-
- // Start the thread to manage the connection and perform transmissions
- mConnectedThread = new ConnectedThread(socket);
- mConnectedThread.start();
- // Send the name of the connected device back to the UI Activity
- Message msg = mHandler.obtainMessage(Constants.MESSAGE_DEVICE_NAME);
- Bundle bundle = new Bundle();
- bundle.putString(Constants.DEVICE_NAME, device.getName());
- msg.setData(bundle);
- mHandler.sendMessage(msg);
- // Update UI title
- updateUserInterfaceTitle();
- }
-
- /**
- * Stop all threads
- */
- public synchronized void stopBT() {
- Log.d(TAG, "stopBT");
- // Cancel the persistent notification.
- mNM.cancel(NOTIFICATION);
-
- if (mConnectThread != null) {
- mConnectThread.cancel();
- mConnectThread = null;
- }
-
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
-
- mState = STATE_NONE;
- // Update UI title
- updateUserInterfaceTitle();
- }
-
- /**
- * Indicate that the connection attempt failed and notify the UI Activity.
- */
- private void connectionFailed() {
- // Send a failure message back to the Activity
- Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST);
- Bundle bundle = new Bundle();
- bundle.putString(Constants.TOAST, "Unable to connect device");
- msg.setData(bundle);
- mHandler.sendMessage(msg);
-
- mState = STATE_NONE;
- // Update UI title
- updateUserInterfaceTitle();
-
- // Start the service over to restart listening mode
- BluetoothChatService.this.startBT();
- }
-
- /**
- * Indicate that the connection was lost and notify the UI Activity.
- */
- private void connectionLost() {
- // Send a failure message back to the Activity
- Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST);
- Bundle bundle = new Bundle();
- bundle.putString(Constants.TOAST, "Device connection was lost");
- msg.setData(bundle);
- mHandler.sendMessage(msg);
-
- mState = STATE_NONE;
- // Update UI title
- updateUserInterfaceTitle();
-
- // Start the service over to restart listening mode
- BluetoothChatService.this.startBT();
- }
-
- public class BluetoothChatServiceI extends Binder {
- BluetoothChatService getService() {
- return BluetoothChatService.this;
- }
-
- void setHandler(Handler handler) {
- mHandler = handler;
- }
- }
-
- /**
- * This thread runs while attempting to make an outgoing connection
- * with a device. It runs straight through; the connection either
- * succeeds or fails.
- */
- class ConnectThread extends Thread {
- private final BluetoothSocket mmSocket;
- private final BluetoothDevice mmDevice;
-
- public ConnectThread(BluetoothDevice device) {
- mmDevice = device;
- BluetoothSocket tmp = null;
-
- // Get a BluetoothSocket for a connection with the
- // given BluetoothDevice
- try {
- tmp = device.createRfcommSocketToServiceRecord(SERIAL_PORT_CLASS);
- } catch (IOException e) {
- Log.e(TAG, "Socket Type: create() failed", e);
- }
- mmSocket = tmp;
- mState = STATE_CONNECTING;
- }
-
- public void run() {
- Log.i(TAG, "BEGIN mConnectThread");
- setName("ConnectThread");
-
- // 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) {
- Log.e(TAG, "unable to close() socket during connection failure", e2);
- }
- connectionFailed();
- return;
- }
-
- // Reset the ConnectThread because we're done
- synchronized (BluetoothChatService.this) {
- mConnectThread = null;
- }
-
- // Start the connected thread
- connected(mmSocket, mmDevice);
- }
-
- public void cancel() {
- try {
- mmSocket.close();
- } catch (IOException e) {
- Log.e(TAG, "close() of socket failed", e);
- }
- }
- }
-
- /**
- * This thread runs during a connection with a remote device.
- * It handles all incoming and outgoing transmissions.
- */
- class ConnectedThread extends Thread {
- private final BluetoothSocket mmSocket;
- private final InputStream mmInStream;
- private final OutputStream mmOutStream;
- private final IConsole mmIConsole;
-
- public ConnectedThread(BluetoothSocket socket) {
- Log.d(TAG, "create ConnectedThread");
- 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) {
- Log.e(TAG, "temp sockets not created", e);
- }
-
- mmInStream = tmpIn;
- mmOutStream = tmpOut;
- mState = STATE_CONNECTED;
-
- mmIConsole = new IConsole(mmInStream, mmOutStream, new IConsole.DataListener() {
- @Override
- public void onData(IConsole.Data data) {
- //Log.i(TAG, "mConnectedThread: onData");
- // Share the sent message back to the UI Activity
- mHandler.obtainMessage(Constants.MESSAGE_DATA, -1, -1, data)
- .sendToTarget();
- }
-
- @Override
- public void onError(Exception e) {
- Log.e(TAG, "mConnectedThread Error: ", e);
-
- if (e instanceof IOException)
- connectionLost();
- }
- }, /* new IConsole.DebugListener() {
- @Override
- public void onRead(byte[] buffer) {
- if (buffer.length > 0) {
- String hexbuf = IConsole.byteArrayToHex(buffer);
-
- // Send the obtained bytes to the UI Activity
- mHandler.obtainMessage(Constants.MESSAGE_READ, hexbuf.length(), -1, hexbuf.getBytes())
- .sendToTarget();
- }
- }
-
- @Override
- public void onWrite(byte[] buffer) {
- String hexbuf = IConsole.byteArrayToHex(buffer);
-
- // Share the sent message back to the UI Activity
- mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, hexbuf.getBytes())
- .sendToTarget();
- }
- }*/ null);
- }
-
- public void run() {
- showNotification();
-
- Log.i(TAG, "BEGIN mConnectedThread");
-
- while (mState == STATE_CONNECTED) {
- if (!mmIConsole.processIO()) {
- Log.i(TAG, "processIO = false");
- break;
- }
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- ; // ignore
- }
- }
- Log.i(TAG, "END mConnectedThread");
- // Cancel the persistent notification.
- mNM.cancel(NOTIFICATION);
- }
-
-
- public boolean setLevel(int level) {
- return mmIConsole.setLevel(level);
- }
-
- public boolean startIConsole() {
- return mmIConsole.start();
- }
-
- public boolean stopIConsole() {
- return mmIConsole.stop();
- }
-
- public void cancel() {
- mmIConsole.stop();
-
- try {
- mmSocket.close();
- } catch (IOException e) {
- Log.e(TAG, "close() of connect socket failed", e);
- }
-
- }
- }
-}
diff --git a/Application/src/main/java/org/surfsite/iconsole/Constants.java b/Application/src/main/java/org/surfsite/iconsole/Constants.java
deleted file mode 100644
index 7733f87..0000000
--- a/Application/src/main/java/org/surfsite/iconsole/Constants.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2014 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 org.surfsite.iconsole;
-
-/**
- * Defines several constants used between {@link BluetoothChatService} and the UI.
- */
-public interface Constants {
-
- // 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;
- public static final int MESSAGE_DATA = 6;
-
- // Key names received from the BluetoothChatService Handler
- public static final String DEVICE_NAME = "device_name";
- public static final String TOAST = "toast";
-
-}
diff --git a/Application/src/main/java/org/surfsite/iconsole/DeviceListActivity.java b/Application/src/main/java/org/surfsite/iconsole/DeviceListActivity.java
deleted file mode 100644
index 1cd2806..0000000
--- a/Application/src/main/java/org/surfsite/iconsole/DeviceListActivity.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2014 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 org.surfsite.iconsole;
-
-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.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import org.surfsite.iconsole.R;
-
-import java.util.Set;
-
-/**
- * This Activity appears as a dialog. It lists any paired devices and
- * devices detected in the area after discovery. When a device is chosen
- * by the user, the MAC address of the device is sent back to the parent
- * Activity in the result Intent.
- */
-public class DeviceListActivity extends Activity {
-
- /**
- * Tag for Log
- */
- private static final String TAG = "DeviceListActivity";
-
- /**
- * Return Intent extra
- */
- public static String EXTRA_DEVICE_ADDRESS = "device_address";
-
- /**
- * Member fields
- */
- private BluetoothAdapter mBtAdapter;
-
- /**
- * Newly discovered devices
- */
- private ArrayAdapter mNewDevicesArrayAdapter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Setup the window
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.activity_device_list);
-
- // Set result CANCELED in case the user backs out
- setResult(Activity.RESULT_CANCELED);
-
- // Initialize the button to perform device discovery
- Button scanButton = (Button) findViewById(R.id.button_scan);
- scanButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- doDiscovery();
- v.setVisibility(View.GONE);
- }
- });
-
- // Initialize array adapters. One for already paired devices and
- // one for newly discovered devices
- ArrayAdapter pairedDevicesArrayAdapter =
- new ArrayAdapter(this, R.layout.device_name);
- mNewDevicesArrayAdapter = new ArrayAdapter(this, R.layout.device_name);
-
- // Find and set up the ListView for paired devices
- ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
- pairedListView.setAdapter(pairedDevicesArrayAdapter);
- pairedListView.setOnItemClickListener(mDeviceClickListener);
-
- // Find and set up the ListView for newly discovered devices
- ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
- newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
- newDevicesListView.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
- Set pairedDevices = mBtAdapter.getBondedDevices();
-
- // If there are paired devices, add each one to the ArrayAdapter
- if (pairedDevices.size() > 0) {
- findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
- for (BluetoothDevice device : pairedDevices) {
- pairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
- }
- } else {
- String noDevices = getResources().getText(R.string.none_paired).toString();
- pairedDevicesArrayAdapter.add(noDevices);
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- // Make sure we're not doing discovery anymore
- if (mBtAdapter != null) {
- mBtAdapter.cancelDiscovery();
- }
-
- // Unregister broadcast listeners
- this.unregisterReceiver(mReceiver);
- }
-
- /**
- * Start device discover with the BluetoothAdapter
- */
- private void doDiscovery() {
- Log.d(TAG, "doDiscovery()");
-
- // Indicate scanning in the title
- setProgressBarIndeterminateVisibility(true);
- setTitle(R.string.scanning);
-
- // Turn on sub-title for new devices
- findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
-
- // If we're already discovering, stopBT it
- if (mBtAdapter.isDiscovering()) {
- mBtAdapter.cancelDiscovery();
- }
-
- // Request discover from BluetoothAdapter
- mBtAdapter.startDiscovery();
- }
-
- /**
- * The on-click listener for all devices in the ListViews
- */
- private AdapterView.OnItemClickListener mDeviceClickListener
- = new AdapterView.OnItemClickListener() {
- public void onItemClick(AdapterView> av, View v, int arg2, long arg3) {
- // Cancel discovery because it's costly and we're about to connect
- mBtAdapter.cancelDiscovery();
-
- // 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(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() {
- @Override
- 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) {
- mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
- }
- // When discovery is finished, change the Activity title
- } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
- setProgressBarIndeterminateVisibility(false);
- setTitle(R.string.select_device);
- if (mNewDevicesArrayAdapter.getCount() == 0) {
- String noDevices = getResources().getText(R.string.none_found).toString();
- mNewDevicesArrayAdapter.add(noDevices);
- }
- }
- }
- };
-
-}
diff --git a/Application/src/main/java/org/surfsite/iconsole/IConsole.java b/Application/src/main/java/org/surfsite/iconsole/IConsole.java
deleted file mode 100644
index a174a25..0000000
--- a/Application/src/main/java/org/surfsite/iconsole/IConsole.java
+++ /dev/null
@@ -1,370 +0,0 @@
-package org.surfsite.iconsole;
-
-import android.support.annotation.Nullable;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.Locale;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Created by harald on 25.04.17.
- */
-
-class IConsole {
- private static final String TAG = "IConsole";
-
- private static final byte[] PING = {(byte) 0xf0, (byte) 0xa0, (byte) 0x01, (byte) 0x01, (byte) 0x92 };
- private static final byte[] INIT_A0 = {(byte) 0xf0, (byte) 0xa0, 0x02, 0x02, (byte) 0x94};
- //private static final byte[] PONG = {(byte) 0xf0, (byte) 0xb0, 0x01, 0x01, (byte) 0xa2};
- private static final byte[] STATUS = {(byte) 0xf0, (byte) 0xa1, 0x01, 0x01, (byte) 0x93};
- private static final byte[] INIT_A3 = {(byte) 0xf0, (byte) 0xa3, 0x01, 0x01, 0x01, (byte) 0x96};
- private static final byte[] INIT_A4 = {(byte) 0xf0, (byte) 0xa4, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, (byte) 0xa0};
- private static final byte[] START = {(byte) 0xf0, (byte) 0xa5, 0x01, 0x01, 0x02, (byte) 0x99};
- private static final byte[] STOP = {(byte) 0xf0, (byte) 0xa5, 0x01, 0x01, 0x04, (byte) 0x9b};
- private static final byte[] READ = {(byte) 0xf0, (byte) 0xa2, 0x01, 0x01, (byte) 0x94};
- private static final byte[] SETLEVEL = {(byte) 0xf0, (byte) 0xa6, 0x01, 0x01, 0x01, (byte)((0xf0+0xa6+3) & 0xFF)};
-
- private enum State {
- BEGIN,
- PING,
- A0,
- A1,
- A1_POST_PING,
- A3,
- A4,
- START,
- STOP,
- READ,
- SETLEVEL,
- }
-
- private State mCurrentState = State.BEGIN;
- private State mNextState = State.PING;
- private boolean mWaitAck = false;
- private int mSetLevel = 1;
- private long mTimesent = 0;
- private int mExpectLen = 0;
- private byte[] mExpectPacket;
- private final InputStream mInputStream;
- private final OutputStream mOutputStream;
- private final DataListener mDataListener;
- private final DebugListener mDebugListener;
-
- IConsole(InputStream inputStream, OutputStream outputStream,
- @Nullable DataListener dataListener, @Nullable DebugListener debugListener) {
- this.mInputStream = inputStream;
- this.mOutputStream = outputStream;
- this.mDataListener = dataListener;
- this.mDebugListener = debugListener;
- }
-
- class Data implements java.io.Serializable {
- long mTime; // in seconds
- int mSpeed10;
- int mRPM;
- int mDistance10;
- int mCalories;
- int mHF;
- int mPower10;
- int mLevel;
-
- Data(long mTime, int mSpeed10, int mRPM, int mDistance10, int mCalories, int mHF, int mPower10, int mLevel) {
- this.mTime = mTime;
- this.mSpeed10 = mSpeed10;
- this.mRPM = mRPM;
- this.mDistance10 = mDistance10;
- this.mCalories = mCalories;
- this.mHF = mHF;
- this.mPower10 = mPower10;
- this.mLevel = mLevel;
- }
-
- Data(byte[] bytes) {
- this.mTime = (((bytes[2]-1) * 24 + bytes[3]-1) * 60 + bytes[4]-1) * 60 + bytes[5]-1 ;
- this.mSpeed10 = 100 * (bytes[ 6] - 1) + bytes[ 7] - 1;
- this.mRPM = 100 * (bytes[ 8] - 1) + bytes[ 9] - 1;
- this.mDistance10 = 100 * (bytes[10] - 1) + bytes[11] - 1;
- this.mCalories = 100 * (bytes[12] - 1) + bytes[13] - 1;
- this.mHF = 100 * (bytes[14] - 1) + bytes[15] - 1;
- this.mPower10 = 100 * (bytes[16] - 1) + bytes[17] - 1;
- this.mLevel = bytes[18] -1;
- }
-
- String getTimeStr() {
- long day, hour, min, sec;
- StringBuilder b = new StringBuilder();
- day = mTime / 60 / 60 / 24;
- if (day > 0)
- b.append(String.format(Locale.US, "%02d:", day));
- hour = (mTime % (60 * 60 * 24)) / 60 / 60;
- if (hour > 0)
- if (day > 0)
- b.append(String.format(Locale.US, "%02d:", hour));
- else
- b.append(String.format(Locale.US, "%d:", hour));
- min = (mTime % (60 * 60)) / 60;
- sec = mTime % 60;
- b.append(String.format(Locale.US, "%02d:%02d", min, sec));
- return b.toString();
- }
-
- }
-
- interface DataListener {
- void onData(Data data);
- void onError(Exception e);
- }
-
- interface DebugListener {
- void onRead(byte[] bytes);
- void onWrite(byte[] bytes);
- }
-
- boolean start() {
- synchronized (this) {
- this.mNextState = State.A0;
- }
- return true;
- }
-
- boolean stop() {
- synchronized (this) {
- this.mNextState = State.STOP;
- }
- return true;
- }
-
- boolean setLevel(int level) {
- synchronized (this) {
- if (mCurrentState != State.READ)
- return false;
-
- this.mNextState = State.SETLEVEL;
- Log.d(TAG, String.format("Set Level to %d", level));
- this.mSetLevel = level;
- }
- return true;
- }
-
- private boolean send(byte[] packet, byte expect, int plen) throws IOException {
- long now = System.currentTimeMillis();
-
- if ((now - mTimesent) < ((mCurrentState == State.READ) ? 500 : 200)) {
- return false;
- }
-
- // Flush input stream
- try {
- //noinspection ResultOfMethodCallIgnored
- mInputStream.skip(mInputStream.available());
- } catch (IOException e) {
- ; // ignore
- }
-
- // Send packet
- mOutputStream.write(packet);
-
- if (null != mDebugListener)
- mDebugListener.onWrite(packet);
- //Log.d(TAG, "sent: " + byteArrayToHex(packet));
-
- mTimesent = System.currentTimeMillis();
- mExpectPacket = packet.clone();
- mExpectPacket[1] = expect;
- mExpectLen = plen;
- mWaitAck = true;
- return true;
- }
-
- private boolean send(byte[] packet) throws IOException {
- return send(packet, (byte)(0xb0 | (packet[1] & 0xF)), packet.length);
- }
-
- private boolean send(byte[] packet, int plen) throws IOException {
- return send(packet, (byte)(0xb0 | (packet[1] & 0xF)), plen);
- }
-
- private boolean send_level(int level) throws IOException {
- byte[] packet = SETLEVEL.clone();
- packet[4] = (byte) (packet[4] + level);
- packet[5] = (byte) ((packet[5] + level) & 0xFF);
- //Log.d(TAG, "send_level");
- return send(packet);
- }
-
- private byte[] wait_ack() throws IOException, TimeoutException {
- byte[] buffer = new byte[mExpectLen];
- int bytes;
-
- long now = System.currentTimeMillis();
-
- if ((now - mTimesent) > 10000) {
- mWaitAck = false;
- return null;
- }
-
- if (mInputStream.available() < mExpectLen) {
- //Log.d(TAG, String.format(Locale.US, "Avail: %d Expected: %d", mInputStream.available(), mExpectLen));
- return null;
- }
-
- bytes = mInputStream.read(buffer);
-
- if (null != mDebugListener) {
- mDebugListener.onRead(Arrays.copyOfRange(buffer, 0, bytes));
- //Log.d(TAG, "wait ack got: " + byteArrayToHex(Arrays.copyOfRange(buffer, 0, bytes)));
- }
-
- //Log.d(TAG, "wait ack checking");
-
- if (bytes != mExpectLen) {
- throw new IOException("Wrong number of bytes read. Expected " + mExpectLen + ", got " + bytes);
- }
-
- if (buffer[0] != mExpectPacket[0]) {
- throw new IOException("Byte 0 wrong. Expected " + String.format("%02x", mExpectPacket[0]) + ", got " + String.format("%02x", buffer[0]));
- }
-
- if (buffer[1] != mExpectPacket[1]) {
- throw new IOException("Byte 1 wrong. Expected " + String.format("%02x", mExpectPacket[1]) + ", got " + String.format("%02x", buffer[1]));
- }
-
- //Log.d(TAG, "wait ack success");
- mWaitAck = false;
-
- return buffer;
- }
-
- private boolean processIOSend() throws IOException {
- switch (mCurrentState) {
- case BEGIN:
- send(PING);
- break;
- case PING:
- send(PING);
- break;
- case A0:
- send(INIT_A0, (byte)0xb7, 6);
- break;
- case A1:
- send(STATUS, 6);
- break;
- case A1_POST_PING:
- send(PING);
- break;
- case A3:
- send(INIT_A3);
- break;
- case A4:
- send(INIT_A4);
- break;
- case START:
- send(START);
- break;
- case STOP:
- send(STOP);
- break;
- case READ:
- send(READ, 21);
- break;
- case SETLEVEL:
- send_level(mSetLevel);
- break;
- }
- return true;
- }
-
- private boolean processIOAck() throws IOException, TimeoutException {
- byte[] got = null;
- got = wait_ack();
- if (null == got) {
- return true;
- }
-
- //Log.d(TAG, "processIOAck next state");
-
- if(mCurrentState == State.READ)
- if (null != mDataListener)
- mDataListener.onData(new Data(got));
-
- mCurrentState = mNextState;
- switch (mNextState) {
- case BEGIN:
- mNextState = State.PING;
- break;
- case PING:
- mNextState = State.PING;
- break;
- case A0:
- mNextState = State.A1;
- break;
- case A1:
- mNextState = State.A1_POST_PING;
- break;
- case A1_POST_PING:
- mNextState = State.A3;
- break;
- case A3:
- mNextState = State.A4;
- break;
- case A4:
- mNextState = State.START;
- break;
- case START:
- mNextState = State.READ;
- break;
- case STOP:
- mNextState = State.PING;
- break;
- case READ:
- mNextState = State.READ;
- break;
- case SETLEVEL:
- mNextState = State.READ;
- break;
- }
- return true;
- }
-
- boolean processIO() {
- //Log.i(TAG, "Begin processIO");
-
- synchronized (this) {
- try {
- if (!mWaitAck) {
- //Log.i(TAG, "processIOSend");
- return processIOSend();
- } else {
- //Log.i(TAG, "processIOAck");
- return processIOAck();
- }
- } catch (Exception e) {
- Log.e(TAG, "processIO", e);
- if (null != mDataListener)
- mDataListener.onError(e);
- return false;
- }
- }
- }
-
- static byte[] hexStringToByteArray(String s) {
- int len = s.length();
- byte[] data = new byte[len / 2];
- for (int i = 0; i < len; i += 2) {
- data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
- + Character.digit(s.charAt(i+1), 16));
- }
- return data;
- }
-
- static String byteArrayToHex(byte[] a) {
- StringBuilder sb = new StringBuilder(a.length * 2);
- for(byte b: a)
- sb.append(String.format("%02x", b));
- return sb.toString();
- }
-}
diff --git a/Application/src/main/java/org/surfsite/iconsole/MainActivity.java b/Application/src/main/java/org/surfsite/iconsole/MainActivity.java
deleted file mode 100644
index b917357..0000000
--- a/Application/src/main/java/org/surfsite/iconsole/MainActivity.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-* Copyright 2013 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 org.surfsite.iconsole;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.ViewAnimator;
-
-import org.surfsite.iconsole.ChannelService.ChannelServiceComm;
-
-
-/**
- * A simple launcher activity containing a summary sample description, sample log and a custom
- * {@link android.support.v4.app.Fragment} which can display a view.
- *
- * For devices with displays with a width of 720dp or greater, the sample log is always visible,
- * on other devices it's visibility is controlled by an item on the Action Bar.
- */
-public class MainActivity extends FragmentActivity {
-
- public static final String TAG = "MainActivity";
-
- // Whether the Log Fragment is currently shown
- private boolean mLogShown;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- if (savedInstanceState == null) {
- FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
- BluetoothChatFragment fragment = new BluetoothChatFragment();
- transaction.replace(R.id.sample_content_fragment, fragment);
- transaction.commit();
- }
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
- ComponentName componentName = startService(new Intent(this, BluetoothChatService.class));
- if (componentName == null)
- Log.e(TAG, "componentName == null");
- else
- Log.i(TAG, "Service started");
- }
-
- @Override
- protected void onDestroy() {
-
- if(isFinishing())
- {
- stopService(new Intent(this, BluetoothChatService.class));
- stopService(new Intent(this, ChannelService.class));
- }
-
- super.onDestroy();
- }
-
-
-
-}
diff --git a/Application/src/main/java/org/surfsite/iconsole/SpeedChannelController.java b/Application/src/main/java/org/surfsite/iconsole/SpeedChannelController.java
deleted file mode 100644
index 7a83b33..0000000
--- a/Application/src/main/java/org/surfsite/iconsole/SpeedChannelController.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright 2012 Dynastream Innovations Inc.
- *
- * 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 org.surfsite.iconsole;
-
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.dsi.ant.channel.AntChannel;
-import com.dsi.ant.channel.AntCommandFailedException;
-import com.dsi.ant.channel.IAntChannelEventHandler;
-import com.dsi.ant.message.ChannelId;
-import com.dsi.ant.message.ChannelType;
-import com.dsi.ant.message.EventCode;
-import com.dsi.ant.message.fromant.ChannelEventMessage;
-import com.dsi.ant.message.fromant.MessageFromAntType;
-import com.dsi.ant.message.ipc.AntMessageParcel;
-
-import java.util.Random;
-
-public class SpeedChannelController {
- // The device type and transmission type to be part of the channel ID message
- private static final int CHANNEL_SPEED_DEVICE_TYPE = 0x7B;
- private static final int CHANNEL_SPEED_TRANSMISSION_TYPE = 1;
-
- // The period and frequency values the channel will be configured to
- private static final int CHANNEL_SPEED_PERIOD = 8118; // 1 Hz
- private static final int CHANNEL_SPEED_FREQUENCY = 57;
-
- private static final String TAG = SpeedChannelController.class.getSimpleName();
- public static final int SPEED_SENSOR_ID = 0x9e3d4b65;
-
- private static Random randGen = new Random();
-
- private AntChannel mAntChannel;
-
- private ChannelEventCallback mChannelEventCallback = new ChannelEventCallback();
-
-
- private boolean mIsOpen;
- double speed = 0.0;
-
- public SpeedChannelController(AntChannel antChannel) {
- mAntChannel = antChannel;
- openChannel();
- }
-
- boolean openChannel() {
- if (null != mAntChannel) {
- if (mIsOpen) {
- Log.w(TAG, "Channel was already open");
- } else {
- // Channel ID message contains device number, type and transmission type. In
- // order for master (TX) channels and slave (RX) channels to connect, they
- // must have the same channel ID, or wildcard (0) is used.
- ChannelId channelId = new ChannelId(SPEED_SENSOR_ID & 0xFFFF,
- CHANNEL_SPEED_DEVICE_TYPE, CHANNEL_SPEED_TRANSMISSION_TYPE);
-
- try {
- // Setting the channel event handler so that we can receive messages from ANT
- mAntChannel.setChannelEventHandler(mChannelEventCallback);
-
- // Performs channel assignment by assigning the type to the channel. Additional
- // features (such as, background scanning and frequency agility) can be enabled
- // by passing an ExtendedAssignment object to assign(ChannelType, ExtendedAssignment).
- mAntChannel.assign(ChannelType.BIDIRECTIONAL_MASTER);
-
- /*
- * Configures the channel ID, messaging period and rf frequency after assigning,
- * then opening the channel.
- *
- * For any additional ANT features such as proximity search or background scanning, refer to
- * the ANT Protocol Doc found at:
- * http://www.thisisant.com/resources/ant-message-protocol-and-usage/
- */
- mAntChannel.setChannelId(channelId);
- mAntChannel.setPeriod(CHANNEL_SPEED_PERIOD);
- mAntChannel.setRfFrequency(CHANNEL_SPEED_FREQUENCY);
- mAntChannel.open();
- mIsOpen = true;
-
- Log.d(TAG, "Opened channel with device number: " + SPEED_SENSOR_ID);
- } catch (RemoteException e) {
- channelError(e);
- } catch (AntCommandFailedException e) {
- // This will release, and therefore unassign if required
- channelError("Open failed", e);
- }
- }
- } else {
- Log.w(TAG, "No channel available");
- }
-
- return mIsOpen;
- }
-
- void channelError(RemoteException e) {
- String logString = "Remote service communication failed.";
-
- Log.e(TAG, logString);
- }
-
- void channelError(String error, AntCommandFailedException e) {
- StringBuilder logString;
-
- if (e.getResponseMessage() != null) {
- String initiatingMessageId = "0x" + Integer.toHexString(
- e.getResponseMessage().getInitiatingMessageId());
- String rawResponseCode = "0x" + Integer.toHexString(
- e.getResponseMessage().getRawResponseCode());
-
- logString = new StringBuilder(error)
- .append(". Command ")
- .append(initiatingMessageId)
- .append(" failed with code ")
- .append(rawResponseCode);
- } else {
- String attemptedMessageId = "0x" + Integer.toHexString(
- e.getAttemptedMessageType().getMessageId());
- String failureReason = e.getFailureReason().toString();
-
- logString = new StringBuilder(error)
- .append(". Command ")
- .append(attemptedMessageId)
- .append(" failed with reason ")
- .append(failureReason);
- }
-
- Log.e(TAG, logString.toString());
-
- mAntChannel.release();
-
- Log.e(TAG, "ANT Command Failed");
- }
-
- public void close() {
- // TODO kill all our resources
- if (null != mAntChannel) {
- mIsOpen = false;
-
- // Releasing the channel to make it available for others.
- // After releasing, the AntChannel instance cannot be reused.
- mAntChannel.release();
- mAntChannel = null;
- }
-
- Log.e(TAG, "Channel Closed");
- }
-
- /**
- * Implements the Channel Event Handler Interface so that messages can be
- * received and channel death events can be handled.
- */
- public class ChannelEventCallback implements IAntChannelEventHandler {
- int revCounts = 0;
- int ucMessageCount = 0;
- byte ucPageChange = 0;
- byte ucExtMesgType = 1;
- long lastTime = 0;
- double way;
- int rev;
- double remWay;
- double wheel = 0.1;
-
- @Override
- public void onChannelDeath() {
- // Display channel death message when channel dies
- Log.e(TAG, "Channel Death");
- }
-
- @Override
- public void onReceiveMessage(MessageFromAntType messageType, AntMessageParcel antParcel) {
- Log.d(TAG, "Rx: " + antParcel);
- Log.d(TAG, "Message Type: " + messageType);
-
- // Switching on message type to handle different types of messages
- switch (messageType) {
- // If data message, construct from parcel and update channel data
- case BROADCAST_DATA:
- // Rx Data
- //updateData(new BroadcastDataMessage(antParcel).getPayload());
- break;
- case ACKNOWLEDGED_DATA:
- // Rx Data
- //updateData(new AcknowledgedDataMessage(antParcel).getPayload());
- break;
- case CHANNEL_EVENT:
- // Constructing channel event message from parcel
- ChannelEventMessage eventMessage = new ChannelEventMessage(antParcel);
- EventCode code = eventMessage.getEventCode();
- Log.d(TAG, "Event Code: " + code);
-
- // Switching on event code to handle the different types of channel events
- switch (code) {
- case TX:
- long unixTime = System.currentTimeMillis() / 1000L;
-
- if (lastTime != 0) {
- way = speed * (unixTime - lastTime) / 3.6 + remWay;
- rev = (int)(way / wheel + 0.5);
- remWay = way - rev * wheel;
- revCounts += rev;
- }
- lastTime = unixTime;
-
- ucPageChange += 0x20;
- ucPageChange &= 0xF0;
- ucMessageCount += 1;
- byte[] payload = new byte[8];
-
- if (ucMessageCount >= 65) {
- if (ucExtMesgType >= 4)
- ucExtMesgType = 1;
-
- if (ucExtMesgType == 1) {
- int halfunixTime = (int) (unixTime / 2L);
- payload[0] = (byte) ((byte) 0x01 | (byte) (ucPageChange & (byte) 0x80));
- payload[1] = (byte) (halfunixTime & 0xFF);
- payload[2] = (byte) ((halfunixTime >> 8) & 0xFF);
- payload[3] = (byte) ((halfunixTime >> 16) & 0xFF);
- }
- else if (ucExtMesgType == 2) {
- payload[0] = (byte) ((byte) 0x02 | (byte) (ucPageChange & (byte) 0x80));
- payload[1] = (byte) 0xFF;
- payload[2] = (byte) ((SPEED_SENSOR_ID >> 16) & 0xFF);
- payload[3] = (byte) ((SPEED_SENSOR_ID >> 24) & 0xFF);
- }
- else if (ucExtMesgType == 3) {
- payload[0] = (byte) ((byte) 0x03 | (byte) (ucPageChange & (byte) 0x80));
- payload[1] = (byte) 0x01;
- payload[2] = (byte) 0x01;
- payload[3] = (byte) 0x01;
- }
- if (ucMessageCount >= 68) {
- ucMessageCount = 0;
- ucExtMesgType += 1;
- }
- } else {
- payload[0] = (byte) (ucPageChange & 0x80);
- payload[1] = (byte) 0xFF;
- payload[2] = (byte) 0xFF;
- payload[3] = (byte) 0xFF;
- }
-
- int unixTime1024 = (int) (unixTime * 1024);
- payload[4] = (byte) (unixTime1024 & 0xFF);
- payload[5] = (byte) ((unixTime1024 >> 8) & 0xFF);
- payload[6] = (byte) (revCounts & 0xFF);
- payload[7] = (byte) ((revCounts >> 8) & 0xFF);
-
- if (mIsOpen) {
- try {
- // Setting the data to be broadcast on the next channel period
- mAntChannel.setBroadcastData(payload);
- } catch (RemoteException e) {
- channelError(e);
- }
- }
- break;
- case CHANNEL_COLLISION:
- ucPageChange += 0x20;
- ucPageChange &= 0xF0;
- ucMessageCount += 1;
- break;
- case RX_SEARCH_TIMEOUT:
- // TODO May want to keep searching
- Log.e(TAG, "No Device Found");
- break;
- case CHANNEL_CLOSED:
- case RX_FAIL:
- case RX_FAIL_GO_TO_SEARCH:
- case TRANSFER_RX_FAILED:
- case TRANSFER_TX_COMPLETED:
- case TRANSFER_TX_FAILED:
- case TRANSFER_TX_START:
- case UNKNOWN:
- // TODO More complex communication will need to handle these events
- break;
- }
- break;
- case ANT_VERSION:
- case BURST_TRANSFER_DATA:
- case CAPABILITIES:
- case CHANNEL_ID:
- case CHANNEL_RESPONSE:
- case CHANNEL_STATUS:
- case SERIAL_NUMBER:
- case OTHER:
- // TODO More complex communication will need to handle these message types
- break;
- }
- }
- }
-}
diff --git a/Application/src/main/res/drawable-hdpi/ic_action_device_access_bluetooth_searching.png b/Application/src/main/res/drawable-hdpi/ic_action_device_access_bluetooth_searching.png
deleted file mode 100755
index fc0491e..0000000
Binary files a/Application/src/main/res/drawable-hdpi/ic_action_device_access_bluetooth_searching.png and /dev/null differ
diff --git a/Application/src/main/res/drawable-hdpi/ic_launcher.png b/Application/src/main/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 886b5e5..0000000
Binary files a/Application/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/Application/src/main/res/drawable-hdpi/tile.9.png b/Application/src/main/res/drawable-hdpi/tile.9.png
deleted file mode 100644
index 1358628..0000000
Binary files a/Application/src/main/res/drawable-hdpi/tile.9.png and /dev/null differ
diff --git a/Application/src/main/res/drawable-ldpi/ic_launcher.png b/Application/src/main/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index c096e03..0000000
Binary files a/Application/src/main/res/drawable-ldpi/ic_launcher.png and /dev/null differ
diff --git a/Application/src/main/res/drawable-mdpi/ic_action_device_access_bluetooth_searching.png b/Application/src/main/res/drawable-mdpi/ic_action_device_access_bluetooth_searching.png
deleted file mode 100755
index d65de02..0000000
Binary files a/Application/src/main/res/drawable-mdpi/ic_action_device_access_bluetooth_searching.png and /dev/null differ
diff --git a/Application/src/main/res/drawable-mdpi/ic_launcher.png b/Application/src/main/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 8f7d374..0000000
Binary files a/Application/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/Application/src/main/res/drawable-xhdpi/ic_action_device_access_bluetooth_searching.png b/Application/src/main/res/drawable-xhdpi/ic_action_device_access_bluetooth_searching.png
deleted file mode 100755
index c4b236e..0000000
Binary files a/Application/src/main/res/drawable-xhdpi/ic_action_device_access_bluetooth_searching.png and /dev/null differ
diff --git a/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/Application/src/main/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 4004b77..0000000
Binary files a/Application/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/Application/src/main/res/drawable-xxhdpi/ic_action_device_access_bluetooth_searching.png b/Application/src/main/res/drawable-xxhdpi/ic_action_device_access_bluetooth_searching.png
deleted file mode 100755
index de26430..0000000
Binary files a/Application/src/main/res/drawable-xxhdpi/ic_action_device_access_bluetooth_searching.png and /dev/null differ
diff --git a/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index bc1632a..0000000
Binary files a/Application/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png b/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 17b50bd..0000000
Binary files a/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/Application/src/main/res/layout-w720dp/activity_main.xml b/Application/src/main/res/layout-w720dp/activity_main.xml
deleted file mode 100755
index 01928e7..0000000
--- a/Application/src/main/res/layout-w720dp/activity_main.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/Application/src/main/res/layout/activity_device_list.xml b/Application/src/main/res/layout/activity_device_list.xml
deleted file mode 100644
index 0eb2c3d..0000000
--- a/Application/src/main/res/layout/activity_device_list.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Application/src/main/res/layout/activity_main.xml b/Application/src/main/res/layout/activity_main.xml
deleted file mode 100755
index 75570ff..0000000
--- a/Application/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
diff --git a/Application/src/main/res/layout/device_name.xml b/Application/src/main/res/layout/device_name.xml
deleted file mode 100644
index 28f57cc..0000000
--- a/Application/src/main/res/layout/device_name.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
diff --git a/Application/src/main/res/layout/fragment_bluetooth_chat.xml b/Application/src/main/res/layout/fragment_bluetooth_chat.xml
deleted file mode 100644
index f47b525..0000000
--- a/Application/src/main/res/layout/fragment_bluetooth_chat.xml
+++ /dev/null
@@ -1,413 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Application/src/main/res/layout/message.xml b/Application/src/main/res/layout/message.xml
deleted file mode 100644
index 28f57cc..0000000
--- a/Application/src/main/res/layout/message.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
diff --git a/Application/src/main/res/menu/bluetooth_chat.xml b/Application/src/main/res/menu/bluetooth_chat.xml
deleted file mode 100644
index 3cc1d01..0000000
--- a/Application/src/main/res/menu/bluetooth_chat.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
diff --git a/Application/src/main/res/values-sw600dp/template-dimens.xml b/Application/src/main/res/values-sw600dp/template-dimens.xml
deleted file mode 100644
index 22074a2..0000000
--- a/Application/src/main/res/values-sw600dp/template-dimens.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
- @dimen/margin_huge
- @dimen/margin_medium
-
-
diff --git a/Application/src/main/res/values-sw600dp/template-styles.xml b/Application/src/main/res/values-sw600dp/template-styles.xml
deleted file mode 100644
index 03d1974..0000000
--- a/Application/src/main/res/values-sw600dp/template-styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
diff --git a/Application/src/main/res/values-v11/template-styles.xml b/Application/src/main/res/values-v11/template-styles.xml
deleted file mode 100644
index 8c1ea66..0000000
--- a/Application/src/main/res/values-v11/template-styles.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/Application/src/main/res/values-v21/base-colors.xml b/Application/src/main/res/values-v21/base-colors.xml
deleted file mode 100644
index 8b6ec3f..0000000
--- a/Application/src/main/res/values-v21/base-colors.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
diff --git a/Application/src/main/res/values-v21/base-template-styles.xml b/Application/src/main/res/values-v21/base-template-styles.xml
deleted file mode 100644
index c778e4f..0000000
--- a/Application/src/main/res/values-v21/base-template-styles.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/Application/src/main/res/values/base-strings.xml b/Application/src/main/res/values/base-strings.xml
deleted file mode 100644
index 46393c7..0000000
--- a/Application/src/main/res/values/base-strings.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
- OpeniConsole
-
-
-
-
diff --git a/Application/src/main/res/values/fragmentview_strings.xml b/Application/src/main/res/values/fragmentview_strings.xml
deleted file mode 100755
index 7b9d9ec..0000000
--- a/Application/src/main/res/values/fragmentview_strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- Show Log
- Hide Log
-
diff --git a/Application/src/main/res/values/strings.xml b/Application/src/main/res/values/strings.xml
deleted file mode 100644
index 8b6a118..0000000
--- a/Application/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-
- You are not connected to a device
- Bluetooth was not enabled. Leaving OpeniConsole.
- connecting...
- connected to %1$s
- not connected
-
-
- scanning for devices...
- select a device to connect
- No devices have been paired
- No devices found
- Paired Devices
- Other Available Devices
- Scan for devices
-
-
- Start
- Stop
- Disconnect
- 00:00:00
- 0.0
- 0
- Level\n1
- 0.0
- 0
- 0
- 0.0
- Level
- OpeniConsole Bluetooth active
- OpeniConsole - TEST
- Connect to iConsole
-
-
diff --git a/Application/src/main/res/values/template-dimens.xml b/Application/src/main/res/values/template-dimens.xml
deleted file mode 100644
index 39e710b..0000000
--- a/Application/src/main/res/values/template-dimens.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
- 4dp
- 8dp
- 16dp
- 32dp
- 64dp
-
-
-
- @dimen/margin_medium
- @dimen/margin_medium
-
-
diff --git a/Application/src/main/res/values/template-styles.xml b/Application/src/main/res/values/template-styles.xml
deleted file mode 100644
index 0af26bc..0000000
--- a/Application/src/main/res/values/template-styles.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 4f22946..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,647 +0,0 @@
-Apache License
---------------
-
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright {yyyy} {name of copyright owner}
-
- 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.
-
-All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav
-and *.ogg) are licensed under the CC-BY-NC license. All other files are
-licensed under the Apache 2 license.
-
-CC-BY-NC License
-----------------
-
-Attribution-NonCommercial-ShareAlike 4.0 International
-
-=======================================================================
-
-Creative Commons Corporation ("Creative Commons") is not a law firm and
-does not provide legal services or legal advice. Distribution of
-Creative Commons public licenses does not create a lawyer-client or
-other relationship. Creative Commons makes its licenses and related
-information available on an "as-is" basis. Creative Commons gives no
-warranties regarding its licenses, any material licensed under their
-terms and conditions, or any related information. Creative Commons
-disclaims all liability for damages resulting from their use to the
-fullest extent possible.
-
-Using Creative Commons Public Licenses
-
-Creative Commons public licenses provide a standard set of terms and
-conditions that creators and other rights holders may use to share
-original works of authorship and other material subject to copyright
-and certain other rights specified in the public license below. The
-following considerations are for informational purposes only, are not
-exhaustive, and do not form part of our licenses.
-
- Considerations for licensors: Our public licenses are
- intended for use by those authorized to give the public
- permission to use material in ways otherwise restricted by
- copyright and certain other rights. Our licenses are
- irrevocable. Licensors should read and understand the terms
- and conditions of the license they choose before applying it.
- Licensors should also secure all rights necessary before
- applying our licenses so that the public can reuse the
- material as expected. Licensors should clearly mark any
- material not subject to the license. This includes other CC-
- licensed material, or material used under an exception or
- limitation to copyright. More considerations for licensors:
- wiki.creativecommons.org/Considerations_for_licensors
-
- Considerations for the public: By using one of our public
- licenses, a licensor grants the public permission to use the
- licensed material under specified terms and conditions. If
- the licensor's permission is not necessary for any reason--for
- example, because of any applicable exception or limitation to
- copyright--then that use is not regulated by the license. Our
- licenses grant only permissions under copyright and certain
- other rights that a licensor has authority to grant. Use of
- the licensed material may still be restricted for other
- reasons, including because others have copyright or other
- rights in the material. A licensor may make special requests,
- such as asking that all changes be marked or described.
- Although not required by our licenses, you are encouraged to
- respect those requests where reasonable. More_considerations
- for the public:
- wiki.creativecommons.org/Considerations_for_licensees
-
-=======================================================================
-
-Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
-Public License
-
-By exercising the Licensed Rights (defined below), You accept and agree
-to be bound by the terms and conditions of this Creative Commons
-Attribution-NonCommercial-ShareAlike 4.0 International Public License
-("Public License"). To the extent this Public License may be
-interpreted as a contract, You are granted the Licensed Rights in
-consideration of Your acceptance of these terms and conditions, and the
-Licensor grants You such rights in consideration of benefits the
-Licensor receives from making the Licensed Material available under
-these terms and conditions.
-
-
-Section 1 -- Definitions.
-
- a. Adapted Material means material subject to Copyright and Similar
- Rights that is derived from or based upon the Licensed Material
- and in which the Licensed Material is translated, altered,
- arranged, transformed, or otherwise modified in a manner requiring
- permission under the Copyright and Similar Rights held by the
- Licensor. For purposes of this Public License, where the Licensed
- Material is a musical work, performance, or sound recording,
- Adapted Material is always produced where the Licensed Material is
- synched in timed relation with a moving image.
-
- b. Adapter's License means the license You apply to Your Copyright
- and Similar Rights in Your contributions to Adapted Material in
- accordance with the terms and conditions of this Public License.
-
- c. BY-NC-SA Compatible License means a license listed at
- creativecommons.org/compatiblelicenses, approved by Creative
- Commons as essentially the equivalent of this Public License.
-
- d. Copyright and Similar Rights means copyright and/or similar rights
- closely related to copyright including, without limitation,
- performance, broadcast, sound recording, and Sui Generis Database
- Rights, without regard to how the rights are labeled or
- categorized. For purposes of this Public License, the rights
- specified in Section 2(b)(1)-(2) are not Copyright and Similar
- Rights.
-
- e. Effective Technological Measures means those measures that, in the
- absence of proper authority, may not be circumvented under laws
- fulfilling obligations under Article 11 of the WIPO Copyright
- Treaty adopted on December 20, 1996, and/or similar international
- agreements.
-
- f. Exceptions and Limitations means fair use, fair dealing, and/or
- any other exception or limitation to Copyright and Similar Rights
- that applies to Your use of the Licensed Material.
-
- g. License Elements means the license attributes listed in the name
- of a Creative Commons Public License. The License Elements of this
- Public License are Attribution, NonCommercial, and ShareAlike.
-
- h. Licensed Material means the artistic or literary work, database,
- or other material to which the Licensor applied this Public
- License.
-
- i. Licensed Rights means the rights granted to You subject to the
- terms and conditions of this Public License, which are limited to
- all Copyright and Similar Rights that apply to Your use of the
- Licensed Material and that the Licensor has authority to license.
-
- j. Licensor means the individual(s) or entity(ies) granting rights
- under this Public License.
-
- k. NonCommercial means not primarily intended for or directed towards
- commercial advantage or monetary compensation. For purposes of
- this Public License, the exchange of the Licensed Material for
- other material subject to Copyright and Similar Rights by digital
- file-sharing or similar means is NonCommercial provided there is
- no payment of monetary compensation in connection with the
- exchange.
-
- l. Share means to provide material to the public by any means or
- process that requires permission under the Licensed Rights, such
- as reproduction, public display, public performance, distribution,
- dissemination, communication, or importation, and to make material
- available to the public including in ways that members of the
- public may access the material from a place and at a time
- individually chosen by them.
-
- m. Sui Generis Database Rights means rights other than copyright
- resulting from Directive 96/9/EC of the European Parliament and of
- the Council of 11 March 1996 on the legal protection of databases,
- as amended and/or succeeded, as well as other essentially
- equivalent rights anywhere in the world.
-
- n. You means the individual or entity exercising the Licensed Rights
- under this Public License. Your has a corresponding meaning.
-
-
-Section 2 -- Scope.
-
- a. License grant.
-
- 1. Subject to the terms and conditions of this Public License,
- the Licensor hereby grants You a worldwide, royalty-free,
- non-sublicensable, non-exclusive, irrevocable license to
- exercise the Licensed Rights in the Licensed Material to:
-
- a. reproduce and Share the Licensed Material, in whole or
- in part, for NonCommercial purposes only; and
-
- b. produce, reproduce, and Share Adapted Material for
- NonCommercial purposes only.
-
- 2. Exceptions and Limitations. For the avoidance of doubt, where
- Exceptions and Limitations apply to Your use, this Public
- License does not apply, and You do not need to comply with
- its terms and conditions.
-
- 3. Term. The term of this Public License is specified in Section
- 6(a).
-
- 4. Media and formats; technical modifications allowed. The
- Licensor authorizes You to exercise the Licensed Rights in
- all media and formats whether now known or hereafter created,
- and to make technical modifications necessary to do so. The
- Licensor waives and/or agrees not to assert any right or
- authority to forbid You from making technical modifications
- necessary to exercise the Licensed Rights, including
- technical modifications necessary to circumvent Effective
- Technological Measures. For purposes of this Public License,
- simply making modifications authorized by this Section 2(a)
- (4) never produces Adapted Material.
-
- 5. Downstream recipients.
-
- a. Offer from the Licensor -- Licensed Material. Every
- recipient of the Licensed Material automatically
- receives an offer from the Licensor to exercise the
- Licensed Rights under the terms and conditions of this
- Public License.
-
- b. Additional offer from the Licensor -- Adapted Material.
- Every recipient of Adapted Material from You
- automatically receives an offer from the Licensor to
- exercise the Licensed Rights in the Adapted Material
- under the conditions of the Adapter's License You apply.
-
- c. No downstream restrictions. You may not offer or impose
- any additional or different terms or conditions on, or
- apply any Effective Technological Measures to, the
- Licensed Material if doing so restricts exercise of the
- Licensed Rights by any recipient of the Licensed
- Material.
-
- 6. No endorsement. Nothing in this Public License constitutes or
- may be construed as permission to assert or imply that You
- are, or that Your use of the Licensed Material is, connected
- with, or sponsored, endorsed, or granted official status by,
- the Licensor or others designated to receive attribution as
- provided in Section 3(a)(1)(A)(i).
-
- b. Other rights.
-
- 1. Moral rights, such as the right of integrity, are not
- licensed under this Public License, nor are publicity,
- privacy, and/or other similar personality rights; however, to
- the extent possible, the Licensor waives and/or agrees not to
- assert any such rights held by the Licensor to the limited
- extent necessary to allow You to exercise the Licensed
- Rights, but not otherwise.
-
- 2. Patent and trademark rights are not licensed under this
- Public License.
-
- 3. To the extent possible, the Licensor waives any right to
- collect royalties from You for the exercise of the Licensed
- Rights, whether directly or through a collecting society
- under any voluntary or waivable statutory or compulsory
- licensing scheme. In all other cases the Licensor expressly
- reserves any right to collect such royalties, including when
- the Licensed Material is used other than for NonCommercial
- purposes.
-
-
-Section 3 -- License Conditions.
-
-Your exercise of the Licensed Rights is expressly made subject to the
-following conditions.
-
- a. Attribution.
-
- 1. If You Share the Licensed Material (including in modified
- form), You must:
-
- a. retain the following if it is supplied by the Licensor
- with the Licensed Material:
-
- i. identification of the creator(s) of the Licensed
- Material and any others designated to receive
- attribution, in any reasonable manner requested by
- the Licensor (including by pseudonym if
- designated);
-
- ii. a copyright notice;
-
- iii. a notice that refers to this Public License;
-
- iv. a notice that refers to the disclaimer of
- warranties;
-
- v. a URI or hyperlink to the Licensed Material to the
- extent reasonably practicable;
-
- b. indicate if You modified the Licensed Material and
- retain an indication of any previous modifications; and
-
- c. indicate the Licensed Material is licensed under this
- Public License, and include the text of, or the URI or
- hyperlink to, this Public License.
-
- 2. You may satisfy the conditions in Section 3(a)(1) in any
- reasonable manner based on the medium, means, and context in
- which You Share the Licensed Material. For example, it may be
- reasonable to satisfy the conditions by providing a URI or
- hyperlink to a resource that includes the required
- information.
- 3. If requested by the Licensor, You must remove any of the
- information required by Section 3(a)(1)(A) to the extent
- reasonably practicable.
-
- b. ShareAlike.
-
- In addition to the conditions in Section 3(a), if You Share
- Adapted Material You produce, the following conditions also apply.
-
- 1. The Adapter's License You apply must be a Creative Commons
- license with the same License Elements, this version or
- later, or a BY-NC-SA Compatible License.
-
- 2. You must include the text of, or the URI or hyperlink to, the
- Adapter's License You apply. You may satisfy this condition
- in any reasonable manner based on the medium, means, and
- context in which You Share Adapted Material.
-
- 3. You may not offer or impose any additional or different terms
- or conditions on, or apply any Effective Technological
- Measures to, Adapted Material that restrict exercise of the
- rights granted under the Adapter's License You apply.
-
-
-Section 4 -- Sui Generis Database Rights.
-
-Where the Licensed Rights include Sui Generis Database Rights that
-apply to Your use of the Licensed Material:
-
- a. for the avoidance of doubt, Section 2(a)(1) grants You the right
- to extract, reuse, reproduce, and Share all or a substantial
- portion of the contents of the database for NonCommercial purposes
- only;
-
- b. if You include all or a substantial portion of the database
- contents in a database in which You have Sui Generis Database
- Rights, then the database in which You have Sui Generis Database
- Rights (but not its individual contents) is Adapted Material,
- including for purposes of Section 3(b); and
-
- c. You must comply with the conditions in Section 3(a) if You Share
- all or a substantial portion of the contents of the database.
-
-For the avoidance of doubt, this Section 4 supplements and does not
-replace Your obligations under this Public License where the Licensed
-Rights include other Copyright and Similar Rights.
-
-
-Section 5 -- Disclaimer of Warranties and Limitation of Liability.
-
- a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
- EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
- AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
- ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
- IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
- WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
- PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
- ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
- KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
- ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
-
- b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
- TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
- NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
- INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
- COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
- USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
- ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
- DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
- IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
-
- c. The disclaimer of warranties and limitation of liability provided
- above shall be interpreted in a manner that, to the extent
- possible, most closely approximates an absolute disclaimer and
- waiver of all liability.
-
-
-Section 6 -- Term and Termination.
-
- a. This Public License applies for the term of the Copyright and
- Similar Rights licensed here. However, if You fail to comply with
- this Public License, then Your rights under this Public License
- terminate automatically.
-
- b. Where Your right to use the Licensed Material has terminated under
- Section 6(a), it reinstates:
-
- 1. automatically as of the date the violation is cured, provided
- it is cured within 30 days of Your discovery of the
- violation; or
-
- 2. upon express reinstatement by the Licensor.
-
- For the avoidance of doubt, this Section 6(b) does not affect any
- right the Licensor may have to seek remedies for Your violations
- of this Public License.
-
- c. For the avoidance of doubt, the Licensor may also offer the
- Licensed Material under separate terms or conditions or stop
- distributing the Licensed Material at any time; however, doing so
- will not terminate this Public License.
-
- d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
- License.
-
-
-Section 7 -- Other Terms and Conditions.
-
- a. The Licensor shall not be bound by any additional or different
- terms or conditions communicated by You unless expressly agreed.
-
- b. Any arrangements, understandings, or agreements regarding the
- Licensed Material not stated herein are separate from and
- independent of the terms and conditions of this Public License.
-
-
-Section 8 -- Interpretation.
-
- a. For the avoidance of doubt, this Public License does not, and
- shall not be interpreted to, reduce, limit, restrict, or impose
- conditions on any use of the Licensed Material that could lawfully
- be made without permission under this Public License.
-
- b. To the extent possible, if any provision of this Public License is
- deemed unenforceable, it shall be automatically reformed to the
- minimum extent necessary to make it enforceable. If the provision
- cannot be reformed, it shall be severed from this Public License
- without affecting the enforceability of the remaining terms and
- conditions.
-
- c. No term or condition of this Public License will be waived and no
- failure to comply consented to unless expressly agreed to by the
- Licensor.
-
- d. Nothing in this Public License constitutes or may be interpreted
- as a limitation upon, or waiver of, any privileges and immunities
- that apply to the Licensor or You, including from the legal
- processes of any jurisdiction or authority.
-
-=======================================================================
-
-Creative Commons is not a party to its public licenses.
-Notwithstanding, Creative Commons may elect to apply one of its public
-licenses to material it publishes and in those instances will be
-considered the "Licensor." Except for the limited purpose of indicating
-that material is shared under a Creative Commons public license or as
-otherwise permitted by the Creative Commons policies published at
-creativecommons.org/policies, Creative Commons does not authorize the
-use of the trademark "Creative Commons" or any other trademark or logo
-of Creative Commons without its prior written consent including,
-without limitation, in connection with any unauthorized modifications
-to any of its public licenses or any other arrangements,
-understandings, or agreements concerning use of licensed material. For
-the avoidance of doubt, this paragraph does not form part of the public
-licenses.
-
-Creative Commons may be contacted at creativecommons.org.
-
diff --git a/README.md b/README.md
deleted file mode 100644
index 13f4a3c..0000000
--- a/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
-
-# OpeniConsole
-
-
-## Description
-OpeniConsole connects to an iConsole+ fitness bike head unit over bluetooth.
-
-You can set the resistance level and all data is displayed.
-
-This application is in beta status and under heavy development.
-
-OpeniConsole is an open source project and you are invited to improve it.
-
-## Download
-Google Play Store [beta testing](https://play.google.com/apps/testing/org.surfsite.iconsole)
-
-## Screenshot
-
-
-## Development
-Contribute via pull requests. If you want to do major contributions, drop me a message and I will create a development group.
-
-### TODO/Ideas
-- workout recording to FIT/TCX/GPX
-- workout profiles
-- Google street view cycling
-- sensor data broadcasting via ANT (works, message me for a howto or look [here](https://github.com/haraldh/iconsole-android/issues/4))
-
-See also my [python prototype](https://github.com/haraldh/iconsole) for the bluetooth protocol reverse engineering and sensor broadcasting.
diff --git a/android_antlib_4-14-0/android_antlib_4-14-0.iml b/android_antlib_4-14-0/android_antlib_4-14-0.iml
new file mode 100644
index 0000000..284b389
--- /dev/null
+++ b/android_antlib_4-14-0/android_antlib_4-14-0.iml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_antlib_4-14/build.gradle b/android_antlib_4-14-0/build.gradle
similarity index 100%
rename from android_antlib_4-14/build.gradle
rename to android_antlib_4-14-0/build.gradle
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/app.iml b/app/app.iml
new file mode 100644
index 0000000..42a4644
--- /dev/null
+++ b/app/app.iml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generateDebugSources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..8973e5e
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,27 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 24
+ buildToolsVersion '27.0.3'
+ defaultConfig {
+ applicationId "xyz.hoyer.iconsole"
+ minSdkVersion 15
+ targetSdkVersion 24
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation 'com.android.support:appcompat-v7:24.2.1'
+ implementation 'com.android.support:support-v4:24.2.1'
+ implementation 'com.android.support.constraint:constraint-layout:1.1.2'
+ implementation project(':android_antlib_4-14-0')
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..4da8cc6
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /home/harald/Android/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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..aa24833
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Application/src/main/java/com/dsi/ant/channel/PredefinedNetwork.java b/app/src/main/java/com/dsi/ant/channel/PredefinedNetwork.java
similarity index 100%
rename from Application/src/main/java/com/dsi/ant/channel/PredefinedNetwork.java
rename to app/src/main/java/com/dsi/ant/channel/PredefinedNetwork.java
diff --git a/Application/src/main/java/org/surfsite/iconsole/PowerChannelController.java b/app/src/main/java/xyz/hoyer/iconsole/ChannelController.java
similarity index 53%
rename from Application/src/main/java/org/surfsite/iconsole/PowerChannelController.java
rename to app/src/main/java/xyz/hoyer/iconsole/ChannelController.java
index 081c641..57bced0 100644
--- a/Application/src/main/java/org/surfsite/iconsole/PowerChannelController.java
+++ b/app/src/main/java/xyz/hoyer/iconsole/ChannelController.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package org.surfsite.iconsole;
+package xyz.hoyer.iconsole;
import android.os.RemoteException;
import android.util.Log;
@@ -23,70 +23,104 @@ import com.dsi.ant.channel.AntCommandFailedException;
import com.dsi.ant.channel.IAntChannelEventHandler;
import com.dsi.ant.message.ChannelId;
import com.dsi.ant.message.ChannelType;
-import com.dsi.ant.message.EventCode;
import com.dsi.ant.message.fromant.AcknowledgedDataMessage;
+import com.dsi.ant.message.fromant.BroadcastDataMessage;
import com.dsi.ant.message.fromant.ChannelEventMessage;
import com.dsi.ant.message.fromant.MessageFromAntType;
import com.dsi.ant.message.ipc.AntMessageParcel;
import java.util.Random;
-public class PowerChannelController {
- public static final int POWER_SENSOR_ID = 0x9e3d4b66;
+public class ChannelController
+{
// The device type and transmission type to be part of the channel ID message
- private static final int CHANNEL_POWER_DEVICE_TYPE = 0x0B;
- private static final int CHANNEL_POWER_TRANSMISSION_TYPE = 5;
+ private static final int CHANNEL_PROOF_DEVICE_TYPE = 0x08;
+ private static final int CHANNEL_PROOF_TRANSMISSION_TYPE = 1;
+
// The period and frequency values the channel will be configured to
- private static final int CHANNEL_POWER_PERIOD = 8182; // 1 Hz
- private static final int CHANNEL_POWER_FREQUENCY = 57;
- private static final String TAG = PowerChannelController.class.getSimpleName();
+ private static final int CHANNEL_PROOF_PERIOD = 32768; // 1 Hz
+ private static final int CHANNEL_PROOF_FREQUENCY = 77;
+
+ private static final String TAG = ChannelController.class.getSimpleName();
+
private static Random randGen = new Random();
- int power = 0;
- int cadence = 0;
+
private AntChannel mAntChannel;
+ private ChannelBroadcastListener mChannelBroadcastListener;
+
private ChannelEventCallback mChannelEventCallback = new ChannelEventCallback();
+
+ private ChannelInfo mChannelInfo;
+
private boolean mIsOpen;
- public PowerChannelController(AntChannel antChannel) {
+ static public abstract class ChannelBroadcastListener
+ {
+ public abstract void onBroadcastChanged(ChannelInfo newInfo);
+ }
+
+ public ChannelController(AntChannel antChannel, boolean isMaster, int deviceId,
+ ChannelBroadcastListener broadcastListener)
+ {
mAntChannel = antChannel;
+ mChannelInfo = new ChannelInfo(deviceId, isMaster, randGen.nextInt(256));
+ mChannelBroadcastListener = broadcastListener;
+
openChannel();
}
-
- boolean openChannel() {
- if (null != mAntChannel) {
- if (mIsOpen) {
+
+
+ boolean openChannel()
+ {
+ if(null != mAntChannel)
+ {
+ if(mIsOpen)
+ {
Log.w(TAG, "Channel was already open");
- } else {
- // Channel ID message contains device number, type and transmission type. In
- // order for master (TX) channels and slave (RX) channels to connect, they
- // must have the same channel ID, or wildcard (0) is used.
- ChannelId channelId = new ChannelId(POWER_SENSOR_ID & 0xFFFF,
- CHANNEL_POWER_DEVICE_TYPE, CHANNEL_POWER_TRANSMISSION_TYPE);
+ }
+ else
+ {
+ /*
+ * Although this reference code sets ChannelType to either a transmitting master or a receiving slave,
+ * the standard for ANT is that channels communication is bidirectional. The use of single-direction
+ * communication in this app is for ease of understanding as reference code. For more information and
+ * any additional features on ANT channel communication, refer to the ANT Protocol Doc found at:
+ * http://www.thisisant.com/resources/ant-message-protocol-and-usage/
+ */
+ ChannelType channelType = (mChannelInfo.isMaster ?
+ ChannelType.BIDIRECTIONAL_MASTER : ChannelType.BIDIRECTIONAL_SLAVE);
- try {
+ // Channel ID message contains device number, type and transmission type. In
+ // order for master (TX) channels and slave (RX) channels to connect, they
+ // must have the same channel ID, or wildcard (0) is used.
+ ChannelId channelId = new ChannelId(mChannelInfo.deviceNumber,
+ CHANNEL_PROOF_DEVICE_TYPE, CHANNEL_PROOF_TRANSMISSION_TYPE);
+
+ try
+ {
// Setting the channel event handler so that we can receive messages from ANT
mAntChannel.setChannelEventHandler(mChannelEventCallback);
-
- // Performs channel assignment by assigning the type to the channel. Additional
- // features (such as, background scanning and frequency agility) can be enabled
+
+ // Performs channel assignment by assigning the type to the channel. Additional
+ // features (such as, background scanning and frequency agility) can be enabled
// by passing an ExtendedAssignment object to assign(ChannelType, ExtendedAssignment).
- mAntChannel.assign(ChannelType.BIDIRECTIONAL_MASTER);
-
+ mAntChannel.assign(channelType);
+
/*
- * Configures the channel ID, messaging period and rf frequency after assigning,
+ * Configures the channel ID, messaging period and rf frequency after assigning,
* then opening the channel.
- *
- * For any additional ANT features such as proximity search or background scanning, refer to
- * the ANT Protocol Doc found at:
+ *
+ * For any additional ANT features such as proximity search or background scanning, refer to
+ * the ANT Protocol Doc found at:
* http://www.thisisant.com/resources/ant-message-protocol-and-usage/
*/
mAntChannel.setChannelId(channelId);
- mAntChannel.setPeriod(CHANNEL_POWER_PERIOD);
- mAntChannel.setRfFrequency(CHANNEL_POWER_FREQUENCY);
+ mAntChannel.setPeriod(CHANNEL_PROOF_PERIOD);
+ mAntChannel.setRfFrequency(CHANNEL_PROOF_FREQUENCY);
mAntChannel.open();
mIsOpen = true;
- Log.d(TAG, "Opened channel with device number: " + POWER_SENSOR_ID);
+ Log.d(TAG, "Opened channel with device number: " + mChannelInfo.deviceNumber);
} catch (RemoteException e) {
channelError(e);
} catch (AntCommandFailedException e) {
@@ -94,177 +128,79 @@ public class PowerChannelController {
channelError("Open failed", e);
}
}
- } else {
+ }
+ else
+ {
Log.w(TAG, "No channel available");
}
-
+
return mIsOpen;
}
-
- void channelError(RemoteException e) {
- String logString = "Remote service communication failed.";
-
- Log.e(TAG, logString);
-
- }
-
- void channelError(String error, AntCommandFailedException e) {
- StringBuilder logString;
-
- if (e.getResponseMessage() != null) {
- String initiatingMessageId = "0x" + Integer.toHexString(
- e.getResponseMessage().getInitiatingMessageId());
- String rawResponseCode = "0x" + Integer.toHexString(
- e.getResponseMessage().getRawResponseCode());
-
- logString = new StringBuilder(error)
- .append(". Command ")
- .append(initiatingMessageId)
- .append(" failed with code ")
- .append(rawResponseCode);
- } else {
- String attemptedMessageId = "0x" + Integer.toHexString(
- e.getAttemptedMessageType().getMessageId());
- String failureReason = e.getFailureReason().toString();
-
- logString = new StringBuilder(error)
- .append(". Command ")
- .append(attemptedMessageId)
- .append(" failed with reason ")
- .append(failureReason);
- }
-
- Log.e(TAG, logString.toString());
-
- mAntChannel.release();
- }
-
- public void close() {
- // TODO kill all our resources
- if (null != mAntChannel) {
- mIsOpen = false;
-
- // Releasing the channel to make it available for others.
- // After releasing, the AntChannel instance cannot be reused.
- mAntChannel.release();
- mAntChannel = null;
- }
-
- Log.e(TAG, "Channel Closed");
- }
-
/**
* Implements the Channel Event Handler Interface so that messages can be
* received and channel death events can be handled.
*/
- public class ChannelEventCallback implements IAntChannelEventHandler {
+ public class ChannelEventCallback implements IAntChannelEventHandler
+ {
+ private void updateData(byte[] data) {
+ mChannelInfo.broadcastData = data;
- int cnt = 0;
- int eventCount = 0;
- int cumulativePower = 0;
-
- @Override
- public void onChannelDeath() {
- // Display channel death message when channel dies
- Log.e(TAG, "Channel Death");
+ mChannelBroadcastListener.onBroadcastChanged(mChannelInfo);
}
+ @Override
+ public void onChannelDeath()
+ {
+ // Display channel death message when channel dies
+ displayChannelError("Channel Death");
+ }
+
@Override
public void onReceiveMessage(MessageFromAntType messageType, AntMessageParcel antParcel) {
- Log.d(TAG, "Rx: " + antParcel);
- Log.d(TAG, "Message Type: " + messageType);
- byte[] payload = new byte[8];
+ Log.d(TAG, "Rx: "+ antParcel);
// Switching on message type to handle different types of messages
- switch (messageType) {
+ switch(messageType)
+ {
// If data message, construct from parcel and update channel data
case BROADCAST_DATA:
// Rx Data
- //updateData(new BroadcastDataMessage(antParcel).getPayload());
+ updateData(new BroadcastDataMessage(antParcel).getPayload());
break;
case ACKNOWLEDGED_DATA:
// Rx Data
- //updateData(new AcknowledgedDataMessage(antParcel).getPayload());
- payload = new AcknowledgedDataMessage(antParcel).getPayload();
- Log.d(TAG, "AcknowledgedDataMessage: " + payload);
-
- if ((payload[0] == 0) && (payload[1] == 1) && (payload[2] == (byte)0xAA)) {
- payload[0] = (byte) 0x01;
- payload[1] = (byte) 0xAC;
- payload[2] = (byte) 0xFF;
- payload[3] = (byte) 0xFF;
- payload[4] = (byte) 0xFF;
- payload[5] = (byte) 0xFF;
- payload[6] = (byte) 0x00;
- payload[7] = (byte) 0x00;
- try {
- // Setting the data to be broadcast on the next channel period
- mAntChannel.setBroadcastData(payload);
- } catch (RemoteException e) {
- channelError(e);
- }
- }
+ updateData(new AcknowledgedDataMessage(antParcel).getPayload());
break;
case CHANNEL_EVENT:
// Constructing channel event message from parcel
ChannelEventMessage eventMessage = new ChannelEventMessage(antParcel);
- EventCode code = eventMessage.getEventCode();
- Log.d(TAG, "Event Code: " + code);
-
+
// Switching on event code to handle the different types of channel events
- switch (code) {
+ switch(eventMessage.getEventCode())
+ {
case TX:
- cnt += 1;
+ // Use old info as this is what remote device has just received
+ mChannelBroadcastListener.onBroadcastChanged(mChannelInfo);
- if (cnt % 61 == 15) {
- payload[0] = (byte) 0x50;
- payload[1] = (byte) 0xFF;
- payload[2] = (byte) 0xFF;
- payload[3] = (byte) 0x01;
- payload[4] = (byte) 0xFF;
- payload[5] = (byte) 0x00;
- payload[6] = (byte) 0x01;
- payload[7] = (byte) 0x00;
- } else if (cnt % 61 == 30) {
- payload[0] = (byte) 0x51;
- payload[1] = (byte) 0xFF;
- payload[2] = (byte) 0xFF;
- payload[3] = (byte) 0x01;
- payload[4] = (byte) ((POWER_SENSOR_ID) & 0xFF);
- payload[5] = (byte) ((POWER_SENSOR_ID >> 8) & 0xFF);
- payload[6] = (byte) ((POWER_SENSOR_ID >> 16) & 0xFF);
- payload[7] = (byte) ((POWER_SENSOR_ID >> 24) & 0xFF);
- } else {
- eventCount = (eventCount + 1) & 0xFF;
- cumulativePower = (cumulativePower + power) & 0xFFFF;
- payload[0] = (byte) 0x10;
- payload[1] = (byte) eventCount;
- payload[2] = (byte) 0xFF;
- payload[3] = (byte) cadence;
- payload[4] = (byte) ((cumulativePower) & 0xFF);
- payload[5] = (byte) ((cumulativePower >> 8) & 0xFF);
- payload[6] = (byte) ((power) & 0xFF);
- payload[7] = (byte) ((power >> 8) & 0xFF);
- }
+ mChannelInfo.broadcastData[0]++;
- if (mIsOpen) {
+ if(mIsOpen)
+ {
try {
// Setting the data to be broadcast on the next channel period
- mAntChannel.setBroadcastData(payload);
+ mAntChannel.setBroadcastData(mChannelInfo.broadcastData);
} catch (RemoteException e) {
channelError(e);
}
}
break;
- case CHANNEL_COLLISION:
- cnt += 1;
- break;
case RX_SEARCH_TIMEOUT:
- // TODO May want to keep searching
- Log.e(TAG, "No Device Found");
+ // TODO May want to keep searching
+ displayChannelError("No Device Found");
break;
case CHANNEL_CLOSED:
+ case CHANNEL_COLLISION:
case RX_FAIL:
case RX_FAIL_GO_TO_SEARCH:
case TRANSFER_RX_FAILED:
@@ -272,7 +208,7 @@ public class PowerChannelController {
case TRANSFER_TX_FAILED:
case TRANSFER_TX_START:
case UNKNOWN:
- // TODO More complex communication will need to handle these events
+ // TODO More complex communication will need to handle these events
break;
}
break;
@@ -284,9 +220,77 @@ public class PowerChannelController {
case CHANNEL_STATUS:
case SERIAL_NUMBER:
case OTHER:
- // TODO More complex communication will need to handle these message types
+ // TODO More complex communication will need to handle these message types
break;
}
}
}
+
+ public ChannelInfo getCurrentInfo()
+ {
+ return mChannelInfo;
+ }
+
+ void displayChannelError(String displayText)
+ {
+ mChannelInfo.die(displayText);
+ mChannelBroadcastListener.onBroadcastChanged(mChannelInfo);
+ }
+
+ void channelError(RemoteException e) {
+ String logString = "Remote service communication failed.";
+
+ Log.e(TAG, logString);
+
+ displayChannelError(logString);
+ }
+
+ void channelError(String error, AntCommandFailedException e) {
+ StringBuilder logString;
+
+ if(e.getResponseMessage() != null) {
+ String initiatingMessageId = "0x"+ Integer.toHexString(
+ e.getResponseMessage().getInitiatingMessageId());
+ String rawResponseCode = "0x"+ Integer.toHexString(
+ e.getResponseMessage().getRawResponseCode());
+
+ logString = new StringBuilder(error)
+ .append(". Command ")
+ .append(initiatingMessageId)
+ .append(" failed with code ")
+ .append(rawResponseCode);
+ } else {
+ String attemptedMessageId = "0x"+ Integer.toHexString(
+ e.getAttemptedMessageType().getMessageId());
+ String failureReason = e.getFailureReason().toString();
+
+ logString = new StringBuilder(error)
+ .append(". Command ")
+ .append(attemptedMessageId)
+ .append(" failed with reason ")
+ .append(failureReason);
+ }
+
+ Log.e(TAG, logString.toString());
+
+ mAntChannel.release();
+
+ displayChannelError("ANT Command Failed");
+ }
+
+ public void close()
+ {
+ // TODO kill all our resources
+ if (null != mAntChannel)
+ {
+ mIsOpen = false;
+
+ // Releasing the channel to make it available for others.
+ // After releasing, the AntChannel instance cannot be reused.
+ mAntChannel.release();
+ mAntChannel = null;
+ }
+
+ displayChannelError("Channel Closed");
+ }
}
diff --git a/app/src/main/java/xyz/hoyer/iconsole/ChannelInfo.java b/app/src/main/java/xyz/hoyer/iconsole/ChannelInfo.java
new file mode 100644
index 0000000..caf7c29
--- /dev/null
+++ b/app/src/main/java/xyz/hoyer/iconsole/ChannelInfo.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Dynastream Innovations Inc.
+ *
+ * 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 xyz.hoyer.iconsole;
+
+import com.dsi.ant.message.fromant.DataMessage;
+
+public class ChannelInfo
+{
+ public final int deviceNumber;
+
+ /** Master / Slave */
+ public final boolean isMaster;
+
+ public byte[] broadcastData = new byte[DataMessage.LENGTH_STANDARD_PAYLOAD];
+
+ public boolean error;
+ private String mErrorMessage;
+
+ public ChannelInfo(int deviceNumber, boolean isMaster, int initialBroadcastValue)
+ {
+ this.deviceNumber = deviceNumber;
+ this.isMaster = isMaster;
+
+ // Not actually concerned with this value, so can cast to byte and lose data without issues
+ broadcastData[0] = (byte)initialBroadcastValue;
+
+ error = false;
+ mErrorMessage = null;
+ }
+
+ public void die(String errorMessage)
+ {
+ error = true;
+ mErrorMessage = errorMessage;
+ }
+
+ public String getErrorString()
+ {
+ return mErrorMessage;
+ }
+}
diff --git a/app/src/main/java/xyz/hoyer/iconsole/ChannelList.java b/app/src/main/java/xyz/hoyer/iconsole/ChannelList.java
new file mode 100644
index 0000000..0106fc5
--- /dev/null
+++ b/app/src/main/java/xyz/hoyer/iconsole/ChannelList.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2012 Dynastream Innovations Inc.
+ *
+ * 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 xyz.hoyer.iconsole;
+
+import com.dsi.ant.channel.ChannelNotAvailableException;
+import xyz.hoyer.iconsole.ChannelService.ChannelChangedListener;
+import xyz.hoyer.iconsole.ChannelService.ChannelServiceComm;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.ListView;
+import android.widget.Toast;
+import android.widget.ToggleButton;
+
+import java.util.ArrayList;
+
+public class ChannelList extends Activity {
+ private static final String TAG = ChannelList.class.getSimpleName();
+
+ private final String PREF_TX_BUTTON_CHECKED_KEY = "ChannelList.TX_BUTTON_CHECKED";
+ private boolean mCreateChannelAsMaster;
+
+ private ChannelServiceComm mChannelService;
+
+ private ArrayList mChannelDisplayList = new ArrayList();
+ private ArrayAdapter mChannelListAdapter;
+ private SparseArray mIdChannelListIndexMap = new SparseArray();
+
+ private boolean mChannelServiceBound = false;
+
+ private void initButtons()
+ {
+ Log.v(TAG, "initButtons...");
+
+ //Register Master/Slave Toggle handler
+ ToggleButton toggleButton_MasterSlave = (ToggleButton)findViewById(R.id.toggleButton_MasterSlave);
+ toggleButton_MasterSlave.setEnabled(mChannelServiceBound);
+ toggleButton_MasterSlave.setChecked(mCreateChannelAsMaster);
+ toggleButton_MasterSlave.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
+ {
+ @Override
+ public void onCheckedChanged(CompoundButton arg0, boolean enabled)
+ {
+ mCreateChannelAsMaster = enabled;
+ }
+ });
+
+ //Register Add Channel Button handler
+ Button button_addChannel = (Button)findViewById(R.id.button_AddChannel);
+ button_addChannel.setEnabled(mChannelServiceBound);
+ button_addChannel.setOnClickListener(new OnClickListener()
+ {
+ @Override
+ public void onClick(View v)
+ {
+ addNewChannel(mCreateChannelAsMaster);
+ }
+ });
+
+ //Register Clear Channels Button handler
+ Button button_clearChannels = (Button)findViewById(R.id.button_ClearChannels);
+ button_clearChannels.setEnabled(mChannelServiceBound);
+ button_clearChannels.setOnClickListener(new OnClickListener()
+ {
+ @Override
+ public void onClick(View v)
+ {
+ clearAllChannels();
+ }
+ });
+
+ Log.v(TAG, "...initButtons");
+ }
+
+ private void initPrefs()
+ {
+ Log.v(TAG, "initPrefs...");
+
+ // Retrieves the app's current state of channel transmission mode
+ // from preferences to handle app resuming.
+ SharedPreferences preferences = getPreferences(MODE_PRIVATE);
+
+ mCreateChannelAsMaster = preferences.getBoolean(PREF_TX_BUTTON_CHECKED_KEY, true);
+
+ Log.v(TAG, "...initPrefs");
+ }
+
+ private void savePrefs()
+ {
+ Log.v(TAG, "savePrefs...");
+
+ // Saves the app's current state of channel transmission mode to preferences
+ SharedPreferences preferences = getPreferences(MODE_PRIVATE);
+ SharedPreferences.Editor editor = preferences.edit();
+
+ editor.putBoolean(PREF_TX_BUTTON_CHECKED_KEY, mCreateChannelAsMaster);
+
+ editor.commit();
+
+ Log.v(TAG, "...savePrefs");
+ }
+
+ private void doBindChannelService()
+ {
+ Log.v(TAG, "doBindChannelService...");
+
+ // Binds to ChannelService. ChannelService binds and manages connection between the
+ // app and the ANT Radio Service
+ Intent bindIntent = new Intent(this, ChannelService.class);
+ startService(bindIntent);
+ mChannelServiceBound = bindService(bindIntent, mChannelServiceConnection, Context.BIND_AUTO_CREATE);
+
+ if(!mChannelServiceBound) //If the bind returns false, run the unbind method to update the GUI
+ doUnbindChannelService();
+
+ Log.i(TAG, " Channel Service binding = "+ mChannelServiceBound);
+
+ Log.v(TAG, "...doBindChannelService");
+ }
+
+ private void doUnbindChannelService()
+ {
+ Log.v(TAG, "doUnbindChannelService...");
+
+ if(mChannelServiceBound)
+ {
+ unbindService(mChannelServiceConnection);
+
+ mChannelServiceBound = false;
+ }
+
+ ((Button)findViewById(R.id.button_ClearChannels)).setEnabled(false);
+ ((Button)findViewById(R.id.button_AddChannel)).setEnabled(false);
+ ((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(false);
+
+ Log.v(TAG, "...doUnbindChannelService");
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Log.v(TAG, "onCreate...");
+
+ mChannelServiceBound = false;
+
+ setContentView(R.layout.activity_fullscreen);
+
+ initPrefs();
+
+ mChannelListAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, mChannelDisplayList);
+ ListView listView_channelList = (ListView)findViewById(R.id.listView_channelList);
+ listView_channelList.setAdapter(mChannelListAdapter);
+
+ if(!mChannelServiceBound) doBindChannelService();
+
+ initButtons();
+
+ Log.v(TAG, "...onCreate");
+ }
+
+ public void onBack() {
+ finish();
+ }
+
+ @Override
+ public void onDestroy()
+ {
+ Log.v(TAG, "onDestroy...");
+
+ doUnbindChannelService();
+
+ if(isFinishing())
+ {
+ stopService(new Intent(this, ChannelService.class));
+ }
+
+ mChannelServiceConnection = null;
+
+ savePrefs();
+
+ Log.v(TAG, "...onDestroy");
+
+ super.onDestroy();
+ }
+
+ private ServiceConnection mChannelServiceConnection = new ServiceConnection()
+ {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder serviceBinder)
+ {
+ Log.v(TAG, "mChannelServiceConnection.onServiceConnected...");
+
+ mChannelService = (ChannelServiceComm) serviceBinder;
+
+ // Sets a listener that handles channel events
+ mChannelService.setOnChannelChangedListener(new ChannelChangedListener()
+ {
+ // Occurs when a channel has new info/data
+ @Override
+ public void onChannelChanged(final ChannelInfo newInfo)
+ {
+ Integer index = mIdChannelListIndexMap.get(newInfo.deviceNumber);
+
+ if(null != index && index.intValue() < mChannelDisplayList.size())
+ {
+ mChannelDisplayList.set(index.intValue(), getDisplayText(newInfo));
+ runOnUiThread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ mChannelListAdapter.notifyDataSetChanged();
+ }
+ });
+ }
+ }
+
+ // Updates the UI to allow/disallow acquiring new channels
+ @Override
+ public void onAllowAddChannel(boolean addChannelAllowed) {
+ // Enable Add Channel button and Master/Slave toggle if
+ // adding channels is allowed
+ ((Button)findViewById(R.id.button_AddChannel)).setEnabled(addChannelAllowed);
+ ((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(addChannelAllowed);
+ }
+ });
+
+ // Initial check when connecting to ChannelService if adding channels is allowed
+ boolean allowAcquireChannel = mChannelService.isAddChannelAllowed();
+ ((Button)findViewById(R.id.button_AddChannel)).setEnabled(allowAcquireChannel);
+ ((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(allowAcquireChannel);
+
+ refreshList();
+
+ Log.v(TAG, "...mChannelServiceConnection.onServiceConnected");
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName arg0)
+ {
+ Log.v(TAG, "mChannelServiceConnection.onServiceDisconnected...");
+
+ // Clearing and disabling when disconnecting from ChannelService
+ mChannelService = null;
+
+ ((Button)findViewById(R.id.button_ClearChannels)).setEnabled(false);
+ ((Button)findViewById(R.id.button_AddChannel)).setEnabled(false);
+ ((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(false);
+
+ Log.v(TAG, "...mChannelServiceConnection.onServiceDisconnected");
+ }
+ };
+
+ // This method is called when 'Add Channel' button is clicked
+ private void addNewChannel(final boolean isMaster)
+ {
+ Log.v(TAG, "addNewChannel...");
+
+ if(null != mChannelService)
+ {
+ ChannelInfo newChannelInfo;
+ try
+ {
+ // Telling the ChannelService to add a new channel. This method
+ // in ChannelService contains code required to acquire an ANT
+ // channel from ANT Radio Service.
+ newChannelInfo = mChannelService.addNewChannel(isMaster);
+ } catch (ChannelNotAvailableException e)
+ {
+ // Occurs when a channel is not available. Printing out the
+ // stack trace will show why no channels are available.
+ Toast.makeText(this, "Channel Not Available", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ if(null != newChannelInfo)
+ {
+ // Adding new channel info to the list
+ addChannelToList(newChannelInfo);
+ mChannelListAdapter.notifyDataSetChanged();
+ }
+ }
+
+ Log.v(TAG, "...addNewChannel");
+ }
+
+ private void refreshList()
+ {
+ Log.v(TAG, "refreshList...");
+
+ if(null != mChannelService)
+ {
+ ArrayList chInfoList = mChannelService.getCurrentChannelInfoForAllChannels();
+
+ mChannelDisplayList.clear();
+ for(ChannelInfo i: chInfoList)
+ {
+ addChannelToList(i);
+ }
+ mChannelListAdapter.notifyDataSetChanged();
+ }
+
+ Log.v(TAG, "...refreshList");
+ }
+
+ private void addChannelToList(ChannelInfo channelInfo)
+ {
+ Log.v(TAG, "addChannelToList...");
+
+ mIdChannelListIndexMap.put(channelInfo.deviceNumber, mChannelDisplayList.size());
+ mChannelDisplayList.add(getDisplayText(channelInfo));
+
+ Log.v(TAG, "...addChannelToList");
+ }
+
+
+ private static String getDisplayText(ChannelInfo channelInfo)
+ {
+ Log.v(TAG, "getDisplayText...");
+ String displayText = null;
+
+ if(channelInfo.error)
+ {
+ displayText = String.format("#%-6d !:%s", channelInfo.deviceNumber, channelInfo.getErrorString());
+ }
+ else
+ {
+ if(channelInfo.isMaster)
+ {
+ displayText = String.format("#%-6d Tx:[%2d]", channelInfo.deviceNumber, channelInfo.broadcastData[0] & 0xFF);
+ }
+ else
+ {
+ displayText = String.format("#%-6d Rx:[%2d]", channelInfo.deviceNumber, channelInfo.broadcastData[0] & 0xFF);
+ }
+ }
+
+ Log.v(TAG, "...getDisplayText");
+
+ return displayText;
+ }
+
+
+ private void clearAllChannels()
+ {
+ Log.v(TAG, "clearAllChannels...");
+
+ if(null != mChannelService)
+ {
+ // Telling ChannelService to close all the channels
+ mChannelService.clearAllChannels();
+
+ mChannelDisplayList.clear();
+ mIdChannelListIndexMap.clear();
+ mChannelListAdapter.notifyDataSetChanged();
+ }
+
+ Log.v(TAG, "...clearAllChannels");
+ }
+}
diff --git a/Application/src/main/java/org/surfsite/iconsole/ChannelService.java b/app/src/main/java/xyz/hoyer/iconsole/ChannelService.java
similarity index 50%
rename from Application/src/main/java/org/surfsite/iconsole/ChannelService.java
rename to app/src/main/java/xyz/hoyer/iconsole/ChannelService.java
index 26ba4cc..fddb3fe 100644
--- a/Application/src/main/java/org/surfsite/iconsole/ChannelService.java
+++ b/app/src/main/java/xyz/hoyer/iconsole/ChannelService.java
@@ -13,7 +13,9 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package org.surfsite.iconsole;
+package xyz.hoyer.iconsole;
+
+import xyz.hoyer.iconsole.ChannelController.ChannelBroadcastListener;
import com.dsi.ant.AntService;
import com.dsi.ant.channel.AntChannel;
@@ -36,22 +38,31 @@ import android.util.SparseArray;
import java.util.ArrayList;
-public class ChannelService extends Service {
+public class ChannelService extends Service
+{
private static final String TAG = "ChannelService";
-
+
+ private Object mCreateChannel_LOCK = new Object();
+
+ SparseArray mChannelControllerList = new SparseArray();
+
+ ChannelChangedListener mListener;
+
+ int channelDeviceIdCounter = 0;
+
private boolean mAntRadioServiceBound;
private AntService mAntRadioService = null;
private AntChannelProvider mAntChannelProvider = null;
private boolean mAllowAddChannel = false;
- PowerChannelController powerChannelController = null;
- SpeedChannelController speedChannelController = null;
- private ServiceConnection mAntRadioServiceConnection = new ServiceConnection() {
+ private ServiceConnection mAntRadioServiceConnection = new ServiceConnection()
+ {
@Override
- public void onServiceConnected(ComponentName name, IBinder service) {
+ public void onServiceConnected(ComponentName name, IBinder service)
+ {
// Must pass in the received IBinder object to correctly construct an AntService object
mAntRadioService = new AntService(service);
-
+
try {
// Getting a channel provider in order to acquire channels
mAntChannelProvider = mAntRadioService.getChannelProvider();
@@ -62,83 +73,142 @@ public class ChannelService extends Service {
// legacy interface is in use, applications can free the ANT
// radio by attempting to acquire a channel.
boolean legacyInterfaceInUse = mAntChannelProvider.isLegacyInterfaceInUse();
-
+
// If there are channels OR legacy interface in use, allow adding channels
- if (mChannelAvailable || legacyInterfaceInUse) {
+ if(mChannelAvailable || legacyInterfaceInUse) {
mAllowAddChannel = true;
- } else {
+ }
+ else {
// If no channels available AND legacy interface is not in use, disallow adding channels
mAllowAddChannel = false;
}
-
-
+
+ if(mAllowAddChannel) {
+ if(null != mListener) {
+ // Send an event that indicates if adding channels is allowed
+ mListener.onAllowAddChannel(mAllowAddChannel);
+ }
+ }
+
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
-
+
@Override
- public void onServiceDisconnected(ComponentName name) {
+ public void onServiceDisconnected(ComponentName name)
+ {
die("Binder Died");
-
+
mAntChannelProvider = null;
mAntRadioService = null;
-
+
+ if(mAllowAddChannel) { mListener.onAllowAddChannel(false); }
mAllowAddChannel = false;
}
-
+
};
-
+
+ public interface ChannelChangedListener
+ {
+ /**
+ * Occurs when a Channel's Info has changed (i.e. a newly created
+ * channel, channel has transmitted or received data, or if channel has
+ * been closed.
+ *
+ * @param newInfo The channel's updated info
+ */
+ void onChannelChanged(ChannelInfo newInfo);
+
+ /**
+ * Occurs when there is adding a channel is being allowed or disallowed.
+ *
+ * @param addChannelAllowed True if adding channels is allowed. False, otherwise.
+ */
+ void onAllowAddChannel(boolean addChannelAllowed);
+ }
+
/**
* The interface used to communicate with the ChannelService
*/
- public class ChannelServiceComm extends Binder {
-
- void setSpeed(double speed) {
- if (null != speedChannelController) {
- speedChannelController.speed = speed;
- }
+ public class ChannelServiceComm extends Binder
+ {
+ /**
+ * Sets the listener to be used for channel changed event callbacks.
+ *
+ * @param listener The listener that will receive events
+ */
+ void setOnChannelChangedListener(ChannelChangedListener listener)
+ {
+ mListener = listener;
}
-
- void setPower(int power) {
- if (null != powerChannelController) {
- powerChannelController.power = power;
+
+ /**
+ * Retrieves the current info for all channels currently added.
+ *
+ * @return A list that contains info for all the channels
+ */
+ ArrayList getCurrentChannelInfoForAllChannels()
+ {
+ ArrayList retList = new ArrayList();
+ for(int i = 0; i < mChannelControllerList.size(); i++)
+ {
+ ChannelController channel = mChannelControllerList.valueAt(i);
+
+ retList.add(channel.getCurrentInfo());
}
+
+ return retList;
}
-
- void setCadence(int cadence) {
- if (null != powerChannelController) {
- powerChannelController.cadence = cadence;
- }
+
+ /**
+ * Acquires and adds a channel from ANT Radio Service
+ *
+ * @param isMaster True if channel is transmitting, False if channel is receiving
+ * @return The info for the newly acquired and added channel
+ * @throws ChannelNotAvailableException
+ */
+ ChannelInfo addNewChannel(final boolean isMaster) throws ChannelNotAvailableException
+ {
+ return createNewChannel(isMaster);
}
-
+
/**
* Closes all channels currently added.
*/
- void clearAllChannels() {
- closeAllChannels();
+ void clearAllChannels() { closeAllChannels(); }
+
+ /**
+ * Queries if adding a channel is allowed.
+ * @return True if adding a channel is allowed. False, otherwise.
+ */
+ boolean isAddChannelAllowed() { return mAllowAddChannel; }
+ }
+
+ private void closeAllChannels()
+ {
+ synchronized (mChannelControllerList)
+ {
+ // Closing all channels in the list
+ for(int i = 0; i < mChannelControllerList.size(); i++)
+ {
+ mChannelControllerList.valueAt(i).close();
+ }
+ mChannelControllerList.clear();
}
- }
-
- public void openAllChannels() throws ChannelNotAvailableException {
- powerChannelController = new PowerChannelController(acquireChannel());
- speedChannelController = new SpeedChannelController(acquireChannel());
+
+ // Reset the device id counter
+ channelDeviceIdCounter = 0;
}
- private void closeAllChannels() {
- if (powerChannelController != null)
- powerChannelController.close();
- if (speedChannelController != null)
- speedChannelController.close();
- powerChannelController = null;
- speedChannelController = null;
- }
-
- AntChannel acquireChannel() throws ChannelNotAvailableException {
+ AntChannel acquireChannel() throws ChannelNotAvailableException
+ {
AntChannel mAntChannel = null;
- if (null != mAntChannelProvider) {
- try {
+ if(null != mAntChannelProvider)
+ {
+ try
+ {
/*
* If applications require a channel with specific capabilities
* (event buffering, background scanning etc.), a Capabilities
@@ -155,81 +225,124 @@ public class ChannelService extends Service {
Log.v(TAG, mNK.toString());
mAntChannel = mAntChannelProvider.acquireChannelOnPrivateNetwork(this, mNK);
*/
- } catch (RemoteException e) {
+ } catch (RemoteException e)
+ {
die("ACP Remote Ex");
}
- }
+ }
return mAntChannel;
}
+
+ public ChannelInfo createNewChannel(final boolean isMaster) throws ChannelNotAvailableException
+ {
+ ChannelController channelController = null;
+
+ synchronized(mCreateChannel_LOCK)
+ {
+ // Acquiring a channel from ANT Radio Service
+ AntChannel antChannel = acquireChannel();
+
+ if(null != antChannel)
+ {
+
+ channelDeviceIdCounter += 1;
+
+ // Constructing a controller that will manage and control the channel
+ channelController = new ChannelController(antChannel, isMaster, channelDeviceIdCounter,
+ new ChannelBroadcastListener()
+ {
+ @Override
+ public void onBroadcastChanged(ChannelInfo newInfo)
+ {
+ // Sending a channel changed event when message from ANT is received
+ mListener.onChannelChanged(newInfo);
+ }
+ });
+
+ mChannelControllerList.put(channelDeviceIdCounter, channelController);
+ }
+ }
+
+ if(null == channelController) return null;
+
+ return channelController.getCurrentInfo();
+ }
@Override
- public IBinder onBind(Intent arg0) {
+ public IBinder onBind(Intent arg0)
+ {
return new ChannelServiceComm();
}
-
+
/**
* Receives AntChannelProvider state changes being sent from ANT Radio Service
*/
- private final BroadcastReceiver mChannelProviderStateChangedReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mChannelProviderStateChangedReceiver = new BroadcastReceiver()
+ {
@Override
- public void onReceive(Context context, Intent intent) {
- if (AntChannelProvider.ACTION_CHANNEL_PROVIDER_STATE_CHANGED.equals(intent.getAction())) {
+ public void onReceive(Context context, Intent intent)
+ {
+ if(AntChannelProvider.ACTION_CHANNEL_PROVIDER_STATE_CHANGED.equals(intent.getAction())) {
boolean update = false;
// Retrieving the data contained in the intent
int numChannels = intent.getIntExtra(AntChannelProvider.NUM_CHANNELS_AVAILABLE, 0);
boolean legacyInterfaceInUse = intent.getBooleanExtra(AntChannelProvider.LEGACY_INTERFACE_IN_USE, false);
-
- if (mAllowAddChannel) {
+
+ if(mAllowAddChannel) {
// Was a acquire channel allowed
// If no channels available AND legacy interface is not in use, disallow acquiring of channels
- if (0 == numChannels && !legacyInterfaceInUse) {
+ if(0 == numChannels && !legacyInterfaceInUse) {
mAllowAddChannel = false;
update = true;
- closeAllChannels();
}
} else {
// Acquire channels not allowed
// If there are channels OR legacy interface in use, allow acquiring of channels
- if (numChannels > 0 || legacyInterfaceInUse) {
+ if(numChannels > 0 || legacyInterfaceInUse) {
mAllowAddChannel = true;
update = true;
- try {
- openAllChannels();
- } catch (ChannelNotAvailableException exception) {
- Log.e(TAG, "Channel not available!!");
- }
}
}
+
+ if(update && (null != mListener)) {
+ // AllowAddChannel has been changed, sending event callback
+ mListener.onAllowAddChannel(mAllowAddChannel);
+ }
}
}
};
-
- private void doBindAntRadioService() {
- if (BuildConfig.DEBUG) Log.v(TAG, "doBindAntRadioService");
-
+
+ private void doBindAntRadioService()
+ {
+ if(BuildConfig.DEBUG) Log.v(TAG, "doBindAntRadioService");
+
// Start listing for channel available intents
registerReceiver(mChannelProviderStateChangedReceiver, new IntentFilter(AntChannelProvider.ACTION_CHANNEL_PROVIDER_STATE_CHANGED));
-
+
// Creating the intent and calling context.bindService() is handled by
// the static bindService() method in AntService
mAntRadioServiceBound = AntService.bindService(this, mAntRadioServiceConnection);
}
-
- private void doUnbindAntRadioService() {
- if (BuildConfig.DEBUG) Log.v(TAG, "doUnbindAntRadioService");
-
+
+ private void doUnbindAntRadioService()
+ {
+ if(BuildConfig.DEBUG) Log.v(TAG, "doUnbindAntRadioService");
+
// Stop listing for channel available intents
- try {
+ try{
unregisterReceiver(mChannelProviderStateChangedReceiver);
} catch (IllegalArgumentException exception) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Attempting to unregister a never registered Channel Provider State Changed receiver.");
+ if(BuildConfig.DEBUG) Log.d(TAG, "Attempting to unregister a never registered Channel Provider State Changed receiver.");
}
-
- if (mAntRadioServiceBound) {
- try {
+
+ if(mAntRadioServiceBound)
+ {
+ try
+ {
unbindService(mAntRadioServiceConnection);
- } catch (IllegalArgumentException e) {
+ }
+ catch(IllegalArgumentException e)
+ {
// Not bound, that's what we want anyway
}
@@ -238,27 +351,29 @@ public class ChannelService extends Service {
}
@Override
- public void onCreate() {
+ public void onCreate()
+ {
super.onCreate();
-
+
mAntRadioServiceBound = false;
-
+
doBindAntRadioService();
-
}
-
+
@Override
- public void onDestroy() {
+ public void onDestroy()
+ {
closeAllChannels();
doUnbindAntRadioService();
mAntChannelProvider = null;
-
+
super.onDestroy();
}
- static void die(String error) {
- Log.e(TAG, "DIE: " + error);
+ static void die(String error)
+ {
+ Log.e(TAG, "DIE: "+ error);
}
-
+
}
diff --git a/app/src/main/res/layout/activity_fullscreen.xml b/app/src/main/res/layout/activity_fullscreen.xml
new file mode 100644
index 0000000..5c63f7d
--- /dev/null
+++ b/app/src/main/res/layout/activity_fullscreen.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..7ce840e
--- /dev/null
+++ b/app/src/main/res/values/attrs.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..227fd33
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,8 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
+ #66000000
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..5072759
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,6 @@
+
+ iconsole
+
+ Dummy Button
+ Buh!
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..dc8a48c
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/test/java/xyz/hoyer/iconsole/ExampleUnitTest.java b/app/src/test/java/xyz/hoyer/iconsole/ExampleUnitTest.java
new file mode 100644
index 0000000..ef7cca3
--- /dev/null
+++ b/app/src/test/java/xyz/hoyer/iconsole/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package xyz.hoyer.iconsole;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index cf780a6..ad6a928 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,7 @@ buildscript {
google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.1.3'
+ classpath 'com.android.tools.build:gradle:3.1.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 8c0fb64..13372ae 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e4259d6..6d88a5d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Mon Apr 12 12:52:47 CEST 2021
+#Fri Jul 06 14:40:55 CEST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/gradlew b/gradlew
index 91a7e26..9d82f78 100755
--- a/gradlew
+++ b/gradlew
@@ -42,11 +42,6 @@ case "`uname`" in
;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
+cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
+cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -114,6 +109,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
diff --git a/iconsole-android.iml b/iconsole-android.iml
index 74be301..62efb8e 100644
--- a/iconsole-android.iml
+++ b/iconsole-android.iml
@@ -1,5 +1,5 @@
-
+
@@ -8,10 +8,10 @@
-
+
+
-
diff --git a/settings.gradle b/settings.gradle
index 7f179be..9bca508 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include 'Application', ':android_antlib_4-14'
+include ':app', ':android_antlib_4-14-0'