From a48e4d40729e736929632ec422fd189ecdfba33b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 4 Jan 2012 20:33:06 -0800 Subject: altosdroid: import code from mjb Signed-off-by: Keith Packard --- .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 357 ++++++++++++++++++++ .../AltosDroid/BluetoothChatService.java | 370 +++++++++++++++++++++ .../altusmetrum/AltosDroid/DeviceListActivity.java | 203 +++++++++++ 3 files changed, 930 insertions(+) create mode 100644 altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java create mode 100644 altosdroid/src/org/altusmetrum/AltosDroid/BluetoothChatService.java create mode 100644 altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java new file mode 100644 index 00000000..844ca39e --- /dev/null +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.altusmetrum.AltosDroid; + +import android.app.Activity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.View.OnClickListener; +import android.view.inputmethod.EditorInfo; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; +import org.altusmetrum.AltosDroid.R; + +/** + * This is the main Activity that displays the current chat session. + */ +public class AltosDroid extends Activity { + // Debugging + private static final String TAG = "BluetoothChat"; + private static final boolean D = true; + + // 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; + + // Key names received from the BluetoothChatService Handler + public static final String DEVICE_NAME = "device_name"; + public static final String TOAST = "toast"; + + // Intent request codes + private static final int REQUEST_CONNECT_DEVICE_SECURE = 1; + private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2; + private static final int REQUEST_ENABLE_BT = 3; + + // Layout Views + private TextView mTitle; + private ListView mConversationView; + private EditText mOutEditText; + private Button mSendButton; + + // Name of the connected device + private String mConnectedDeviceName = null; + // Array adapter for the conversation thread + private ArrayAdapter mConversationArrayAdapter; + // String buffer for outgoing messages + private StringBuffer mOutStringBuffer; + // Local Bluetooth adapter + private BluetoothAdapter mBluetoothAdapter = null; + // Member object for the chat services + private BluetoothChatService mChatService = null; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if(D) Log.e(TAG, "+++ ON CREATE +++"); + + // Set up the window layout + requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); + setContentView(R.layout.main); + getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title); + + // Set up the custom title + mTitle = (TextView) findViewById(R.id.title_left_text); + mTitle.setText(R.string.app_name); + mTitle = (TextView) findViewById(R.id.title_right_text); + + // Get local Bluetooth adapter + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + + // If the adapter is null, then Bluetooth is not supported + if (mBluetoothAdapter == null) { + Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show(); + finish(); + return; + } + } + + @Override + public void onStart() { + super.onStart(); + if(D) Log.e(TAG, "++ ON START ++"); + + // If BT is not on, request that it be enabled. + // setupChat() will then be called during onActivityResult + if (!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(); + } + } + + @Override + public synchronized void onResume() { + super.onResume(); + if(D) Log.e(TAG, "+ ON RESUME +"); + + // 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.start(); + } + } + } + + private void setupChat() { + Log.d(TAG, "setupChat()"); + + // Initialize the array adapter for the conversation thread + mConversationArrayAdapter = new ArrayAdapter(this, R.layout.message); + mConversationView = (ListView) findViewById(R.id.in); + mConversationView.setAdapter(mConversationArrayAdapter); + + // Initialize the compose field with a listener for the return key + mOutEditText = (EditText) findViewById(R.id.edit_text_out); + mOutEditText.setOnEditorActionListener(mWriteListener); + + // Initialize the send button with a listener that for click events + mSendButton = (Button) findViewById(R.id.button_send); + mSendButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + // Send a message using content of the edit text widget + TextView view = (TextView) findViewById(R.id.edit_text_out); + String message = view.getText().toString(); + sendMessage(message); + } + }); + + // Initialize the BluetoothChatService to perform bluetooth connections + mChatService = new BluetoothChatService(this, mHandler); + + // Initialize the buffer for outgoing messages + mOutStringBuffer = new StringBuffer(""); + } + + @Override + public synchronized void onPause() { + super.onPause(); + if(D) Log.e(TAG, "- ON PAUSE -"); + } + + @Override + public void onStop() { + super.onStop(); + if(D) Log.e(TAG, "-- ON STOP --"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + // Stop the Bluetooth chat services + if (mChatService != null) mChatService.stop(); + if(D) Log.e(TAG, "--- ON DESTROY ---"); + } + + private void ensureDiscoverable() { + if(D) Log.d(TAG, "ensure discoverable"); + 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) { + // Check that we're actually connected before trying anything + if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) { + Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show(); + return; + } + + // Check that there's actually something to send + if (message.length() > 0) { + // Get the message bytes and tell the BluetoothChatService to write + byte[] send = message.getBytes(); + mChatService.write(send); + + // Reset out string buffer to zero and clear the edit text field + mOutStringBuffer.setLength(0); + mOutEditText.setText(mOutStringBuffer); + } + } + + // The action listener for the EditText widget, to listen for the return key + private TextView.OnEditorActionListener mWriteListener = + new TextView.OnEditorActionListener() { + public boolean onEditorAction(TextView view, int actionId, KeyEvent event) { + // If the action is a key-up event on the return key, send the message + if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) { + String message = view.getText().toString(); + sendMessage(message); + } + if(D) Log.i(TAG, "END onEditorAction"); + return true; + } + }; + + // The Handler that gets information back from the BluetoothChatService + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MESSAGE_STATE_CHANGE: + if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); + switch (msg.arg1) { + case BluetoothChatService.STATE_CONNECTED: + mTitle.setText(R.string.title_connected_to); + mTitle.append(mConnectedDeviceName); + mConversationArrayAdapter.clear(); + break; + case BluetoothChatService.STATE_CONNECTING: + mTitle.setText(R.string.title_connecting); + break; + case BluetoothChatService.STATE_READY: + case BluetoothChatService.STATE_NONE: + mTitle.setText(R.string.title_not_connected); + break; + } + break; + case MESSAGE_WRITE: + byte[] writeBuf = (byte[]) msg.obj; + // construct a string from the buffer + String writeMessage = new String(writeBuf); + mConversationArrayAdapter.add("Me: " + writeMessage); + break; + case 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 MESSAGE_DEVICE_NAME: + // save the connected device's name + mConnectedDeviceName = msg.getData().getString(DEVICE_NAME); + Toast.makeText(getApplicationContext(), "Connected to " + + mConnectedDeviceName, Toast.LENGTH_SHORT).show(); + break; + case MESSAGE_TOAST: + Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST), + Toast.LENGTH_SHORT).show(); + break; + } + } + }; + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if(D) Log.d(TAG, "onActivityResult " + resultCode); + 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_CONNECT_DEVICE_INSECURE: + // When DeviceListActivity returns with a device to connect + if (resultCode == Activity.RESULT_OK) { + connectDevice(data, false); + } + 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 occured + Log.d(TAG, "BT not enabled"); + Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show(); + finish(); + } + } + } + + 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 + mChatService.connect(device, secure); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.option_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + Intent serverIntent = null; + switch (item.getItemId()) { + case R.id.secure_connect_scan: + // Launch the DeviceListActivity to see devices and do scan + serverIntent = new Intent(this, DeviceListActivity.class); + startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE); + return true; + case R.id.insecure_connect_scan: + // Launch the DeviceListActivity to see devices and do scan + serverIntent = new Intent(this, DeviceListActivity.class); + startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE); + return true; + case R.id.discoverable: + // Ensure this device is discoverable by others + ensureDiscoverable(); + return true; + } + return false; + } + +} diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/BluetoothChatService.java b/altosdroid/src/org/altusmetrum/AltosDroid/BluetoothChatService.java new file mode 100644 index 00000000..93cb75de --- /dev/null +++ b/altosdroid/src/org/altusmetrum/AltosDroid/BluetoothChatService.java @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.altusmetrum.AltosDroid; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +//import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSocket; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +/** + * 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 { + // Debugging + private static final String TAG = "BluetoothChatService"; + private static final boolean D = true; + + // Member fields + private final BluetoothAdapter mAdapter; + private final Handler mHandler; + private ConnectThread mConnectThread; + private ConnectedThread mConnectedThread; + private int mState; + + // Constants that indicate the current connection state + public static final int STATE_NONE = 0; // we're doing nothing + public static final int STATE_READY = 1; + 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 + + /** + * Constructor. Prepares a new BluetoothChat session. + * @param context The UI Activity Context + * @param handler A Handler to send messages back to the UI Activity + */ + public BluetoothChatService(Context context, Handler handler) { + mAdapter = BluetoothAdapter.getDefaultAdapter(); + mState = STATE_NONE; + mHandler = handler; + } + + /** + * Set the current state of the chat connection + * @param state An integer defining the current connection state + */ + private synchronized void setState(int state) { + if (D) Log.d(TAG, "setState() " + mState + " -> " + state); + mState = state; + + // Give the new state to the Handler so the UI Activity can update + mHandler.obtainMessage(AltosDroid.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); + } + + /** + * Return the current connection state. */ + public synchronized int getState() { + return mState; + } + + /** + * Start the chat service. Specifically start AcceptThread to begin a + * session in listening (server) mode. Called by the Activity onResume() */ + public synchronized void start() { + if (D) Log.d(TAG, "start"); + + // Cancel any thread attempting to make a connection + if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} + + // Cancel any thread currently running a connection + if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} + + setState(STATE_READY); + + } + + /** + * Start the ConnectThread to initiate a connection to a remote device. + * @param device The BluetoothDevice to connect + * @param secure Socket Security type - Secure (true) , Insecure (false) + */ + public synchronized void connect(BluetoothDevice device, boolean secure) { + if (D) 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, secure); + mConnectThread.start(); + setState(STATE_CONNECTING); + } + + /** + * Start the ConnectedThread to begin managing a Bluetooth connection + * @param socket The BluetoothSocket on which the connection was made + * @param device The BluetoothDevice that has been connected + */ + public synchronized void connected(BluetoothSocket socket, BluetoothDevice + device, final String socketType) { + if (D) Log.d(TAG, "connected, Socket Type:" + socketType); + + // Cancel the thread that completed the connection + if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} + + // Cancel any thread currently running a connection + if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} + + // Start the thread to manage the connection and perform transmissions + mConnectedThread = new ConnectedThread(socket, socketType); + mConnectedThread.start(); + + // Send the name of the connected device back to the UI Activity + Message msg = mHandler.obtainMessage(AltosDroid.MESSAGE_DEVICE_NAME); + Bundle bundle = new Bundle(); + bundle.putString(AltosDroid.DEVICE_NAME, device.getName()); + msg.setData(bundle); + mHandler.sendMessage(msg); + + setState(STATE_CONNECTED); + } + + /** + * Stop all threads + */ + public synchronized void stop() { + if (D) Log.d(TAG, "stop"); + + if (mConnectThread != null) { + mConnectThread.cancel(); + mConnectThread = null; + } + + if (mConnectedThread != null) { + mConnectedThread.cancel(); + mConnectedThread = null; + } + + setState(STATE_NONE); + } + + /** + * Write to the ConnectedThread in an unsynchronized manner + * @param out The bytes to write + * @see ConnectedThread#write(byte[]) + */ + public void write(byte[] out) { + // Create temporary object + ConnectedThread r; + // Synchronize a copy of the ConnectedThread + synchronized (this) { + if (mState != STATE_CONNECTED) return; + r = mConnectedThread; + } + // Perform the write unsynchronized + r.write(out); + } + + /** + * Indicate that the connection attempt failed and notify the UI Activity. + */ + private void connectionFailed() { + // Send a failure message back to the Activity + Message msg = mHandler.obtainMessage(AltosDroid.MESSAGE_TOAST); + Bundle bundle = new Bundle(); + bundle.putString(AltosDroid.TOAST, "Unable to connect device"); + msg.setData(bundle); + mHandler.sendMessage(msg); + + // Start the service over to restart listening mode + BluetoothChatService.this.start(); + } + + /** + * 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(AltosDroid.MESSAGE_TOAST); + Bundle bundle = new Bundle(); + bundle.putString(AltosDroid.TOAST, "Device connection was lost"); + msg.setData(bundle); + mHandler.sendMessage(msg); + + // Start the service over to restart listening mode + BluetoothChatService.this.start(); + } + + + /** + * This thread runs while attempting to make an outgoing connection + * with a device. It runs straight through; the connection either + * succeeds or fails. + */ + private class ConnectThread extends Thread { + private final BluetoothSocket mmSocket; + private final BluetoothDevice mmDevice; + private String mSocketType; + + public ConnectThread(BluetoothDevice device, boolean secure) { + mmDevice = device; + BluetoothSocket tmp = null; + mSocketType = secure ? "Secure" : "Insecure"; + + // Get a BluetoothSocket for a connection with the + // given BluetoothDevice + try { + if (secure) { + Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}); + tmp = (BluetoothSocket) m.invoke(device, 2); +// tmp = device.createRfcommSocket(1); + } else { + Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class}); + tmp = (BluetoothSocket) m.invoke(device, 2); +// tmp = device.createInsecureRfcommSocket(1); + } + } catch (Exception e) { + Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e); + e.printStackTrace(); + } + mmSocket = tmp; + } + + public void run() { + Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType); + setName("ConnectThread" + mSocketType); + + // 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() " + mSocketType + + " 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, mSocketType); + } + + public void cancel() { + try { + mmSocket.close(); + } catch (IOException e) { + Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e); + } + } + } + + /** + * This thread runs during a connection with a remote device. + * It handles all incoming and outgoing transmissions. + */ + private class ConnectedThread extends Thread { + private final BluetoothSocket mmSocket; + private final InputStream mmInStream; + private final OutputStream mmOutStream; + + public ConnectedThread(BluetoothSocket socket, String socketType) { + Log.d(TAG, "create ConnectedThread: " + socketType); + mmSocket = socket; + InputStream tmpIn = null; + OutputStream tmpOut = null; + + // Get the BluetoothSocket input and output streams + try { + tmpIn = socket.getInputStream(); + tmpOut = socket.getOutputStream(); + } catch (IOException e) { + Log.e(TAG, "temp sockets not created", e); + } + + mmInStream = tmpIn; + mmOutStream = tmpOut; + } + + public void run() { + Log.i(TAG, "BEGIN mConnectedThread"); + byte[] buffer = new byte[1024]; + int bytes; + + // Keep listening to the InputStream while connected + while (true) { + try { + // Read from the InputStream + bytes = mmInStream.read(buffer); + + // Send the obtained bytes to the UI Activity + mHandler.obtainMessage(AltosDroid.MESSAGE_READ, bytes, -1, buffer) + .sendToTarget(); + } catch (IOException e) { + Log.e(TAG, "disconnected", e); + connectionLost(); + break; + } + } + } + + /** + * Write to the connected OutStream. + * @param buffer The bytes to write + */ + public void write(byte[] buffer) { + try { + mmOutStream.write(buffer); + + // Share the sent message back to the UI Activity + mHandler.obtainMessage(AltosDroid.MESSAGE_WRITE, -1, -1, buffer) + .sendToTarget(); + } catch (IOException e) { + Log.e(TAG, "Exception during write", e); + } + } + + public void cancel() { + try { + mmSocket.close(); + } catch (IOException e) { + Log.e(TAG, "close() of connect socket failed", e); + } + } + } +} diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java b/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java new file mode 100644 index 00000000..af5d7f15 --- /dev/null +++ b/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.altusmetrum.AltosDroid; + +import java.util.Set; +import org.altusmetrum.AltosDroid.R; + +import android.app.Activity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.Window; +import android.view.View.OnClickListener; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.AdapterView.OnItemClickListener; + +/** + * 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 { + // Debugging + private static final String TAG = "DeviceListActivity"; + private static final boolean D = true; + + // Return Intent extra + public static String EXTRA_DEVICE_ADDRESS = "device_address"; + + // Member fields + private BluetoothAdapter mBtAdapter; + private ArrayAdapter mPairedDevicesArrayAdapter; + private ArrayAdapter mNewDevicesArrayAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Setup the window + requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); + setContentView(R.layout.device_list); + + // Set result CANCELED incase 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 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 + mPairedDevicesArrayAdapter = 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(mPairedDevicesArrayAdapter); + 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) { + mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); + } + } else { + String noDevices = getResources().getText(R.string.none_paired).toString(); + mPairedDevicesArrayAdapter.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() { + if (D) 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, stop it + if (mBtAdapter.isDiscovering()) { + mBtAdapter.cancelDiscovery(); + } + + // Request discover from BluetoothAdapter + mBtAdapter.startDiscovery(); + } + + // The on-click listener for all devices in the ListViews + private OnItemClickListener mDeviceClickListener = new OnItemClickListener() { + public void onItemClick(AdapterView av, View v, int arg2, long arg3) { + // Cancel discovery because it's costly and we're about to connect + 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); + } + } + } + }; + +} -- cgit v1.2.3 From 9b659904109f992b8a3e61efb94e81cdb19af1c9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 23 Feb 2012 16:37:24 +1300 Subject: Demonstrate using AltosLib from altosdroid Get things hooked up so that we can use AltosLib functions from the android application; it's a bit of a hack at present, but appears to work. Some more 'official' technique would be nice... Signed-off-by: Keith Packard --- altosdroid/.classpath | 1 + altosdroid/Makefile.am | 10 ++++++++-- altosdroid/local.properties.in | 1 + altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java | 3 +++ 4 files changed, 13 insertions(+), 2 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/.classpath b/altosdroid/.classpath index 6efcbb73..d260cafa 100644 --- a/altosdroid/.classpath +++ b/altosdroid/.classpath @@ -1,6 +1,7 @@ + diff --git a/altosdroid/Makefile.am b/altosdroid/Makefile.am index 2c6ffc2c..557a5722 100644 --- a/altosdroid/Makefile.am +++ b/altosdroid/Makefile.am @@ -23,6 +23,12 @@ SRC=\ all: $(all_target) +ALTOSLIB=bin/classes/AltosLib.jar + +$(ALTOSLIB): + mkdir -p bin/classes + cd bin/classes && ln -s ../../../altoslib/AltosLib.jar . + if ANDROID install-release: bin/AltosDroid-release.apk $(ADB) install -r bin/AltosDroid-release.apk @@ -30,10 +36,10 @@ install-release: bin/AltosDroid-release.apk install-debug: bin/AltosDroid-debug.apk $(ADB) install -r bin/AltosDroid-debug.apk -bin/AltosDroid-debug.apk: $(SRC) +bin/AltosDroid-debug.apk: $(SRC) $(ALTOSLIB) ant debug -bin/AltosDroid-release.apk: $(SRC) +bin/AltosDroid-release.apk: $(SRC) $(ALTOSLIB) ant release endif diff --git a/altosdroid/local.properties.in b/altosdroid/local.properties.in index 14df0494..543ce208 100644 --- a/altosdroid/local.properties.in +++ b/altosdroid/local.properties.in @@ -8,3 +8,4 @@ # For customization when using a Version Control System, please read the # header note. sdk.dir=@ANDROID_SDK@ +extensible.libs.classpath=../altoslib diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 844ca39e..87f89cf9 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -39,6 +39,7 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import org.altusmetrum.AltosDroid.R; +import org.altusmetrum.AltosLib.*; /** * This is the main Activity that displays the current chat session. @@ -48,6 +49,8 @@ public class AltosDroid extends Activity { private static final String TAG = "BluetoothChat"; private static final boolean D = true; + private static final AltosLine q = new AltosLine(); + // Message types sent from the BluetoothChatService Handler public static final int MESSAGE_STATE_CHANGE = 1; public static final int MESSAGE_READ = 2; -- cgit v1.2.3 From 392c878000e9909d37dae6342df3d6cb8f217a1b Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Thu, 23 Feb 2012 16:41:26 +1300 Subject: Add TelemetryService.java and associated files Signed-off-by: Mike Beattie --- altosdroid/AndroidManifest.xml | 27 ++++ altosdroid/Makefile.am | 2 + altosdroid/res/drawable-hdpi/am_status.png | Bin 0 -> 804 bytes altosdroid/res/drawable-mdpi/am_status.png | Bin 0 -> 595 bytes .../res/layout/telemetry_service_binding.xml | 42 +++++ .../res/layout/telemetry_service_controller.xml | 42 +++++ altosdroid/res/menu/option_menu.xml | 6 + altosdroid/res/values/strings.xml | 26 ++++ .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 8 + .../altusmetrum/AltosDroid/TelemetryService.java | 109 +++++++++++++ .../AltosDroid/TelemetryServiceActivities.java | 171 +++++++++++++++++++++ 11 files changed, 433 insertions(+) create mode 100644 altosdroid/res/drawable-hdpi/am_status.png create mode 100644 altosdroid/res/drawable-mdpi/am_status.png create mode 100644 altosdroid/res/layout/telemetry_service_binding.xml create mode 100644 altosdroid/res/layout/telemetry_service_controller.xml create mode 100644 altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java create mode 100644 altosdroid/src/org/altusmetrum/AltosDroid/TelemetryServiceActivities.java (limited to 'altosdroid/src') diff --git a/altosdroid/AndroidManifest.xml b/altosdroid/AndroidManifest.xml index b72f0384..1d55737d 100644 --- a/altosdroid/AndroidManifest.xml +++ b/altosdroid/AndroidManifest.xml @@ -34,5 +34,32 @@ android:label="@string/select_device" android:theme="@android:style/Theme.Dialog" android:configChanges="orientation|keyboardHidden" /> + + + + + + + + + + + + + + diff --git a/altosdroid/Makefile.am b/altosdroid/Makefile.am index 557a5722..0732087b 100644 --- a/altosdroid/Makefile.am +++ b/altosdroid/Makefile.am @@ -18,6 +18,8 @@ SRC_DIR=src/org/altusmetrum/AltosDroid SRC=\ $(SRC_DIR)/AltosDroid.java \ + $(SRC_DIR)/TelemetryService.java \ + $(SRC_DIR)/TelemetryServiceActivities.java \ $(SRC_DIR)/BluetoothChatService.java \ $(SRC_DIR)/DeviceListActivity.java diff --git a/altosdroid/res/drawable-hdpi/am_status.png b/altosdroid/res/drawable-hdpi/am_status.png new file mode 100644 index 00000000..03f9dd7d Binary files /dev/null and b/altosdroid/res/drawable-hdpi/am_status.png differ diff --git a/altosdroid/res/drawable-mdpi/am_status.png b/altosdroid/res/drawable-mdpi/am_status.png new file mode 100644 index 00000000..07f7f073 Binary files /dev/null and b/altosdroid/res/drawable-mdpi/am_status.png differ diff --git a/altosdroid/res/layout/telemetry_service_binding.xml b/altosdroid/res/layout/telemetry_service_binding.xml new file mode 100644 index 00000000..950d0d3a --- /dev/null +++ b/altosdroid/res/layout/telemetry_service_binding.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + diff --git a/altosdroid/res/layout/telemetry_service_controller.xml b/altosdroid/res/layout/telemetry_service_controller.xml new file mode 100644 index 00000000..189d2f6c --- /dev/null +++ b/altosdroid/res/layout/telemetry_service_controller.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + diff --git a/altosdroid/res/menu/option_menu.xml b/altosdroid/res/menu/option_menu.xml index 18de725c..27625e9c 100644 --- a/altosdroid/res/menu/option_menu.xml +++ b/altosdroid/res/menu/option_menu.xml @@ -14,6 +14,12 @@ limitations under the License. --> + + diff --git a/altosdroid/res/values/strings.xml b/altosdroid/res/values/strings.xml index 60823b12..0b2f9227 100644 --- a/altosdroid/res/values/strings.xml +++ b/altosdroid/res/values/strings.xml @@ -38,4 +38,30 @@ Connect a device - Secure Connect a device - Insecure Make discoverable + + + AltOS Telemetry Service + Telemetry Service Started + Telemetry Service Stopped + + + + Start/Stop Service + Bind/Unbind Service + + App/Service/Local Service Controller + This demonstrates how you can implement persistent services that + may be started and stopped as desired. + Start Service + Stop Service + + App/Service/Local Service Binding + This demonstrates how you can connect with a persistent + service. Notice how it automatically starts for you, and play around with the + interaction between this and Local Service Controller. + Bind Service + Unbind Service + Connected to local service + Disconnected from local service + diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 87f89cf9..b4a3227c 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -339,6 +339,14 @@ public class AltosDroid extends Activity { public boolean onOptionsItemSelected(MenuItem item) { Intent serverIntent = null; switch (item.getItemId()) { + case R.id.telemetry_service_control: + serverIntent = new Intent(this, TelemetryServiceActivities.Controller.class); + startActivity(serverIntent); + return true; + case R.id.telemetry_service_bind: + serverIntent = new Intent(this, TelemetryServiceActivities.Binding.class); + startActivity(serverIntent); + return true; case R.id.secure_connect_scan: // Launch the DeviceListActivity to see devices and do scan serverIntent = new Intent(this, DeviceListActivity.class); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java new file mode 100644 index 00000000..40dff354 --- /dev/null +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2007 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.altusmetrum.AltosDroid; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; +import android.util.Log; +import android.widget.Toast; + +// Need the following import to get access to the app resources, since this +// class is in a sub-package. +import org.altusmetrum.AltosDroid.R; + + + +public class TelemetryService extends Service { + private NotificationManager mNM; + + // Unique Identification Number for the Notification. + // We use it on Notification start, and to cancel it. + private int NOTIFICATION = R.string.telemetry_service_started; + + /** + * Class for clients to access. Because we know this service always + * runs in the same process as its clients, we don't need to deal with + * IPC. + */ + public class TelemetryBinder extends Binder { + TelemetryService getService() { + return TelemetryService.this; + } + } + + @Override + public void onCreate() { + mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + + // Display a notification about us starting. We put an icon in the status bar. + showNotification(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.i("TelemetryService", "Received start id " + startId + ": " + intent); + // We want this service to continue running until it is explicitly + // stopped, so return sticky. + return START_STICKY; + } + + @Override + public void onDestroy() { + // Cancel the persistent notification. + mNM.cancel(NOTIFICATION); + + // Tell the user we stopped. + Toast.makeText(this, R.string.telemetry_service_stopped, Toast.LENGTH_SHORT).show(); + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + // This is the object that receives interactions from clients. See + // RemoteService for a more complete example. + private final IBinder mBinder = new TelemetryBinder(); + + /** + * 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.telemetry_service_started); + + // Set the icon, scrolling text and timestamp + Notification notification = new Notification(R.drawable.am_status, text, + System.currentTimeMillis()); + + // The PendingIntent to launch our activity if the user selects this notification + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, + new Intent(this, TelemetryServiceActivities.Controller.class), 0); + + // Set the info for the views that show in the notification panel. + notification.setLatestEventInfo(this, getText(R.string.telemetry_service_label), + text, contentIntent); + + // Send the notification. + mNM.notify(NOTIFICATION, notification); + } +} diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryServiceActivities.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryServiceActivities.java new file mode 100644 index 00000000..5191cfa9 --- /dev/null +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryServiceActivities.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2007 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.altusmetrum.AltosDroid; + +import org.altusmetrum.AltosDroid.R; + +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.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.Toast; + +public class TelemetryServiceActivities { + /** + *

Example of explicitly starting and stopping the local service. + * This demonstrates the implementation of a service that runs in the same + * process as the rest of the application, which is explicitly started and stopped + * as desired.

+ * + *

Note that this is implemented as an inner class only keep the sample + * all together; typically this code would appear in some separate class. + */ + public static class Controller extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.telemetry_service_controller); + + // Watch for button clicks. + Button button = (Button)findViewById(R.id.start); + button.setOnClickListener(mStartListener); + button = (Button)findViewById(R.id.stop); + button.setOnClickListener(mStopListener); + } + + private OnClickListener mStartListener = new OnClickListener() { + public void onClick(View v) { + // Make sure the service is started. It will continue running + // until someone calls stopService(). The Intent we use to find + // the service explicitly specifies our service component, because + // we want it running in our own process and don't want other + // applications to replace it. + startService(new Intent(Controller.this, + TelemetryService.class)); + } + }; + + private OnClickListener mStopListener = new OnClickListener() { + public void onClick(View v) { + // Cancel a previous call to startService(). Note that the + // service will not actually stop at this point if there are + // still bound clients. + stopService(new Intent(Controller.this, + TelemetryService.class)); + } + }; + } + + // ---------------------------------------------------------------------- + + /** + * Example of binding and unbinding to the local service. + * This demonstrates the implementation of a service which the client will + * bind to, receiving an object through which it can communicate with the service.

+ * + *

Note that this is implemented as an inner class only keep the sample + * all together; typically this code would appear in some separate class. + */ + public static class Binding extends Activity { + private boolean mIsBound; + + + private TelemetryService mBoundService; + + 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. + mBoundService = ((TelemetryService.TelemetryBinder)service).getService(); + + // Tell the user about this for our demo. + Toast.makeText(Binding.this, R.string.telemetry_service_connected, + Toast.LENGTH_SHORT).show(); + } + + 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. + mBoundService = null; + Toast.makeText(Binding.this, R.string.telemetry_service_disconnected, + Toast.LENGTH_SHORT).show(); + } + }; + + void 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). + bindService(new Intent(Binding.this, + TelemetryService.class), mConnection, Context.BIND_AUTO_CREATE); + mIsBound = true; + } + + void doUnbindService() { + if (mIsBound) { + // Detach our existing connection. + unbindService(mConnection); + mIsBound = false; + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + doUnbindService(); + } + + + private OnClickListener mBindListener = new OnClickListener() { + public void onClick(View v) { + doBindService(); + } + }; + + private OnClickListener mUnbindListener = new OnClickListener() { + public void onClick(View v) { + doUnbindService(); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.telemetry_service_binding); + + // Watch for button clicks. + Button button = (Button)findViewById(R.id.bind); + button.setOnClickListener(mBindListener); + button = (Button)findViewById(R.id.unbind); + button.setOnClickListener(mUnbindListener); + } + } +} -- cgit v1.2.3 From b242f2756a8d9419a9bdba890b9e6b73560bdc19 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 18 Jul 2012 00:03:54 -0700 Subject: altosdroid: Start adding an AltosLink subclass for android Will talks over bluetooth while providing an AltosLink APi Signed-off-by: Keith Packard --- .../org/altusmetrum/AltosDroid/AltosBluetooth.java | 191 +++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java new file mode 100644 index 00000000..45438a6c --- /dev/null +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -0,0 +1,191 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosDroid; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Method; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSocket; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import org.altusmetrum.AltosLib.*; + +public class AltosBluetooth extends AltosLink { + + // Debugging + private static final String TAG = "AltosBluetooth"; + private static final boolean D = true; + + /** + * This thread runs while attempting to make an outgoing connection + * with a device. It runs straight through; the connection either + * succeeds or fails. + */ + + private BluetoothAdapter adapter; + private ConnectThread connect_thread; + private BluetoothSocket socket; + private InputStream input; + private OutputStream output; + + private class ConnectThread extends Thread { + private final BluetoothDevice mmDevice; + private String mSocketType; + BluetoothSocket tmp_socket; + + public ConnectThread(BluetoothDevice device, boolean secure) { + mmDevice = device; + mSocketType = secure ? "Secure" : "Insecure"; + + // Get a BluetoothSocket for a connection with the + // given BluetoothDevice + try { + if (secure) { + Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}); + tmp_socket = (BluetoothSocket) m.invoke(device, 2); + // tmp = device.createRfcommSocket(2); + } else { + Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class}); + tmp_socket = (BluetoothSocket) m.invoke(device, 2); + // tmp = device.createInsecureRfcommSocket(2); + } + } catch (Exception e) { + Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e); + e.printStackTrace(); + } + } + + public void run() { + Log.i(TAG, "BEGIN connect_thread SocketType:" + mSocketType); + setName("ConnectThread" + mSocketType); + + // Always cancel discovery because it will slow down a connection + adapter.cancelDiscovery(); + + // Make a connection to the BluetoothSocket + try { + // This is a blocking call and will only return on a + // successful connection or an exception + tmp_socket.connect(); + } catch (IOException e) { + // Close the socket + try { + tmp_socket.close(); + } catch (IOException e2) { + Log.e(TAG, "unable to close() " + mSocketType + + " socket during connection failure", e2); + } + connection_failed(); + return; + } + + try { + synchronized (AltosBluetooth.this) { + input = tmp_socket.getInputStream(); + output = tmp_socket.getOutputStream(); + socket = tmp_socket; + // Reset the ConnectThread because we're done + AltosBluetooth.this.notify(); + connect_thread = null; + } + } catch (Exception e) { + Log.e(TAG, "Failed to finish connection", e); + e.printStackTrace(); + } + } + + public void cancel() { + try { + if (tmp_socket != null) + tmp_socket.close(); + } catch (IOException e) { + Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e); + } + } + } + + private synchronized void wait_connected() throws InterruptedException { + if (input == null) { + wait(); + } + } + + private void connection_failed() { + } + + public void print(String data) { + byte[] bytes = data.getBytes(); + try { + wait_connected(); + output.write(bytes); + } catch (IOException e) { + connection_failed(); + } catch (InterruptedException e) { + connection_failed(); + } + } + + public int getchar() { + try { + wait_connected(); + return input.read(); + } catch (IOException e) { + connection_failed(); + } catch (java.lang.InterruptedException e) { + connection_failed(); + } + return AltosLink.ERROR; + } + + public void close() { + synchronized(this) { + if (connect_thread != null) { + connect_thread.cancel(); + connect_thread = null; + } + } + } + + public void flush_output() { + super.flush_output(); + /* any local work needed to flush bluetooth? */ + } + + public boolean can_cancel_reply() { + return false; + } + public boolean show_reply_timeout() { + return true; + } + + public void hide_reply_timeout() { + } + + public AltosBluetooth(BluetoothDevice device) { + adapter = BluetoothAdapter.getDefaultAdapter(); + connect_thread = new ConnectThread(device, true); + connect_thread.start(); + } +} \ No newline at end of file -- cgit v1.2.3 From 359d7353fd7b7d4d537db04c5e89724502333ff8 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Thu, 2 Aug 2012 22:09:24 +1200 Subject: AltosDroid: Begin re-working Bluetooth code * Move to using explicit 'magic' UUID, rather than java reflection * Re-work UI to make it more useful for testing * Use Insecure RFCOMM only, and remove code that differentiates. Signed-off-by: Mike Beattie --- altosdroid/res/layout/main.xml | 24 +++-- altosdroid/res/menu/option_menu.xml | 12 +-- altosdroid/res/values/strings.xml | 14 +-- .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 111 ++++++++------------- .../AltosDroid/BluetoothChatService.java | 54 ++++------ 5 files changed, 83 insertions(+), 132 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/res/layout/main.xml b/altosdroid/res/layout/main.xml index 17025f6b..f2e6640c 100644 --- a/altosdroid/res/layout/main.xml +++ b/altosdroid/res/layout/main.xml @@ -19,24 +19,30 @@ android:layout_width="match_parent" android:layout_height="match_parent" > - + android:gravity="bottom" + android:scrollbars="vertical" + android:typeface="monospace" /> + - + android:layout_weight="1" + android:inputType="text|textNoSuggestions" /> + - - - - - diff --git a/altosdroid/res/layout/telemetry_service_controller.xml b/altosdroid/res/layout/telemetry_service_controller.xml deleted file mode 100644 index 189d2f6c..00000000 --- a/altosdroid/res/layout/telemetry_service_controller.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/altosdroid/res/menu/option_menu.xml b/altosdroid/res/menu/option_menu.xml index feb5668e..6946e298 100644 --- a/altosdroid/res/menu/option_menu.xml +++ b/altosdroid/res/menu/option_menu.xml @@ -17,10 +17,4 @@ - -

diff --git a/altosdroid/res/values/strings.xml b/altosdroid/res/values/strings.xml index 72a4ddec..e3234fc7 100644 --- a/altosdroid/res/values/strings.xml +++ b/altosdroid/res/values/strings.xml @@ -36,31 +36,11 @@ Connect a device - Control Service - (Un)Bind Service - - AltosDroid Telemetry Service Telemetry Service Started Telemetry Service Stopped - - Telemetry Service Controller - Use the following buttons to start and stop the Telemetry - service. - Start Service - Stop Service - - Telemetry Service Binding - This demonstrates how you can connect with a persistent - service. Notice how it automatically starts for you, and play around with the - interaction between this and Local Service Controller. - Bind Service - Unbind Service - - Connected to local service - Disconnected from local service diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 29d72d95..92ba5587 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -321,14 +321,6 @@ public class AltosDroid extends Activity { public boolean onOptionsItemSelected(MenuItem item) { Intent serverIntent = null; switch (item.getItemId()) { - case R.id.telemetry_service_control: - serverIntent = new Intent(this, TelemetryServiceActivities.Controller.class); - startActivity(serverIntent); - return true; - case R.id.telemetry_service_bind: - serverIntent = new Intent(this, TelemetryServiceActivities.Binding.class); - startActivity(serverIntent); - return true; case R.id.connect_scan: // Launch the DeviceListActivity to see devices and do scan serverIntent = new Intent(this, DeviceListActivity.class); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index a1c5fede..95b655c2 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -67,7 +67,7 @@ public class TelemetryService extends Service { // The PendingIntent to launch our activity if the user selects this notification PendingIntent contentIntent = PendingIntent.getActivity(this, 0, - new Intent(this, TelemetryServiceActivities.Controller.class), 0); + new Intent(this, AltosDroid.class), 0); // Set the info for the views that show in the notification panel. notification.setLatestEventInfo(this, getText(R.string.telemetry_service_label), text, contentIntent); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryServiceActivities.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryServiceActivities.java deleted file mode 100644 index 5191cfa9..00000000 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryServiceActivities.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2007 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.altusmetrum.AltosDroid; - -import org.altusmetrum.AltosDroid.R; - -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.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.Toast; - -public class TelemetryServiceActivities { - /** - *

Example of explicitly starting and stopping the local service. - * This demonstrates the implementation of a service that runs in the same - * process as the rest of the application, which is explicitly started and stopped - * as desired.

- * - *

Note that this is implemented as an inner class only keep the sample - * all together; typically this code would appear in some separate class. - */ - public static class Controller extends Activity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.telemetry_service_controller); - - // Watch for button clicks. - Button button = (Button)findViewById(R.id.start); - button.setOnClickListener(mStartListener); - button = (Button)findViewById(R.id.stop); - button.setOnClickListener(mStopListener); - } - - private OnClickListener mStartListener = new OnClickListener() { - public void onClick(View v) { - // Make sure the service is started. It will continue running - // until someone calls stopService(). The Intent we use to find - // the service explicitly specifies our service component, because - // we want it running in our own process and don't want other - // applications to replace it. - startService(new Intent(Controller.this, - TelemetryService.class)); - } - }; - - private OnClickListener mStopListener = new OnClickListener() { - public void onClick(View v) { - // Cancel a previous call to startService(). Note that the - // service will not actually stop at this point if there are - // still bound clients. - stopService(new Intent(Controller.this, - TelemetryService.class)); - } - }; - } - - // ---------------------------------------------------------------------- - - /** - * Example of binding and unbinding to the local service. - * This demonstrates the implementation of a service which the client will - * bind to, receiving an object through which it can communicate with the service.

- * - *

Note that this is implemented as an inner class only keep the sample - * all together; typically this code would appear in some separate class. - */ - public static class Binding extends Activity { - private boolean mIsBound; - - - private TelemetryService mBoundService; - - 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. - mBoundService = ((TelemetryService.TelemetryBinder)service).getService(); - - // Tell the user about this for our demo. - Toast.makeText(Binding.this, R.string.telemetry_service_connected, - Toast.LENGTH_SHORT).show(); - } - - 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. - mBoundService = null; - Toast.makeText(Binding.this, R.string.telemetry_service_disconnected, - Toast.LENGTH_SHORT).show(); - } - }; - - void 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). - bindService(new Intent(Binding.this, - TelemetryService.class), mConnection, Context.BIND_AUTO_CREATE); - mIsBound = true; - } - - void doUnbindService() { - if (mIsBound) { - // Detach our existing connection. - unbindService(mConnection); - mIsBound = false; - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - doUnbindService(); - } - - - private OnClickListener mBindListener = new OnClickListener() { - public void onClick(View v) { - doBindService(); - } - }; - - private OnClickListener mUnbindListener = new OnClickListener() { - public void onClick(View v) { - doUnbindService(); - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.telemetry_service_binding); - - // Watch for button clicks. - Button button = (Button)findViewById(R.id.bind); - button.setOnClickListener(mBindListener); - button = (Button)findViewById(R.id.unbind); - button.setOnClickListener(mUnbindListener); - } - } -} -- cgit v1.2.3 From 80bf63702175322053f2b38c4fff56b653ab7c70 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 14:52:30 +1200 Subject: altosdroid: excise BluetoothChatService example code Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 75 +---- .../AltosDroid/BluetoothChatService.java | 354 --------------------- 2 files changed, 11 insertions(+), 418 deletions(-) delete mode 100644 altosdroid/src/org/altusmetrum/AltosDroid/BluetoothChatService.java (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 92ba5587..521588fb 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -64,10 +64,6 @@ public class AltosDroid extends Activity { private EditText mOutEditText; private Button mSendButton; - // String buffer for outgoing messages - private StringBuffer mOutStringBuffer; - // Member object for the chat services - private BluetoothChatService mChatService = null; // Intent request codes private static final int REQUEST_CONNECT_DEVICE = 1; private static final int REQUEST_ENABLE_BT = 2; @@ -115,7 +111,7 @@ public class AltosDroid extends Activity { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); } else { - if (mChatService == null) setupChat(); + //if (mChatService == null) setupChat(); } } @@ -127,13 +123,13 @@ public class AltosDroid extends Activity { // 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.start(); - } - } + //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.start(); + //} + //} } @Override @@ -151,13 +147,12 @@ public class AltosDroid extends Activity { @Override public void onDestroy() { super.onDestroy(); - // Stop the Bluetooth chat services - if (mChatService != null) mChatService.stop(); if(D) Log.e(TAG, "--- ON DESTROY ---"); } +/* private void setupChat() { Log.d(TAG, "setupChat()"); @@ -187,6 +182,7 @@ public class AltosDroid extends Activity { // Initialize the buffer for outgoing messages mOutStringBuffer = new StringBuffer(""); } +*/ /** * Sends a message. @@ -228,54 +224,6 @@ public class AltosDroid extends Activity { }; */ - // The Handler that gets information back from the BluetoothChatService - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_STATE_CHANGE: - if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); - switch (msg.arg1) { - case BluetoothChatService.STATE_CONNECTED: - mTitle.setText(R.string.title_connected_to); - mTitle.append(mConnectedDeviceName); - mSerialView.setText(""); - break; - case BluetoothChatService.STATE_CONNECTING: - mTitle.setText(R.string.title_connecting); - break; - case BluetoothChatService.STATE_READY: - case BluetoothChatService.STATE_NONE: - mTitle.setText(R.string.title_not_connected); - break; - } - break; - case MESSAGE_WRITE: - byte[] writeBuf = (byte[]) msg.obj; - // construct a string from the buffer - String writeMessage = new String(writeBuf); - mSerialView.append(writeMessage + '\n'); - break; - case 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); - mSerialView.append(readMessage); - break; - case MESSAGE_DEVICE_NAME: - // save the connected device's name - mConnectedDeviceName = msg.getData().getString(DEVICE_NAME); - Toast.makeText(getApplicationContext(), "Connected to " - + mConnectedDeviceName, Toast.LENGTH_SHORT).show(); - break; - case MESSAGE_TOAST: - Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST), - Toast.LENGTH_SHORT).show(); - break; - } - } - }; - public void onActivityResult(int requestCode, int resultCode, Intent data) { if(D) Log.d(TAG, "onActivityResult " + resultCode); switch (requestCode) { @@ -289,7 +237,7 @@ public class AltosDroid extends Activity { // When the request to enable Bluetooth returns if (resultCode == Activity.RESULT_OK) { // Bluetooth is now enabled, so set up a chat session - setupChat(); + //setupChat(); } else { // User did not enable Bluetooth or an error occured Log.d(TAG, "BT not enabled"); @@ -306,7 +254,6 @@ public class AltosDroid extends Activity { // Get the BLuetoothDevice object BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); // Attempt to connect to the device - mChatService.connect(device); } diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/BluetoothChatService.java b/altosdroid/src/org/altusmetrum/AltosDroid/BluetoothChatService.java deleted file mode 100644 index a93c08d6..00000000 --- a/altosdroid/src/org/altusmetrum/AltosDroid/BluetoothChatService.java +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.altusmetrum.AltosDroid; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.UUID; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothSocket; -import android.content.Context; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.util.Log; - -/** - * 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 { - // Debugging - private static final String TAG = "BluetoothChatService"; - private static final boolean D = true; - - // Member fields - private final BluetoothAdapter mAdapter; - private final Handler mHandler; - private ConnectThread mConnectThread; - private ConnectedThread mConnectedThread; - private int mState; - - // Constants that indicate the current connection state - public static final int STATE_NONE = 0; // we're doing nothing - public static final int STATE_READY = 1; - 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 - - /** - * Constructor. Prepares a new BluetoothChat session. - * @param context The UI Activity Context - * @param handler A Handler to send messages back to the UI Activity - */ - public BluetoothChatService(Context context, Handler handler) { - mAdapter = BluetoothAdapter.getDefaultAdapter(); - mState = STATE_NONE; - mHandler = handler; - } - - /** - * Set the current state of the chat connection - * @param state An integer defining the current connection state - */ - private synchronized void setState(int state) { - if (D) Log.d(TAG, "setState() " + mState + " -> " + state); - mState = state; - - // Give the new state to the Handler so the UI Activity can update - mHandler.obtainMessage(AltosDroid.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); - } - - /** - * Return the current connection state. */ - public synchronized int getState() { - return mState; - } - - /** - * Start the chat service. Specifically start AcceptThread to begin a - * session in listening (server) mode. Called by the Activity onResume() */ - public synchronized void start() { - if (D) Log.d(TAG, "start"); - - // Cancel any thread attempting to make a connection - if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} - - // Cancel any thread currently running a connection - if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} - - setState(STATE_READY); - - } - - /** - * Start the ConnectThread to initiate a connection to a remote device. - * @param device The BluetoothDevice to connect - */ - public synchronized void connect(BluetoothDevice device) { - if (D) 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(); - setState(STATE_CONNECTING); - } - - /** - * Start the ConnectedThread to begin managing a Bluetooth connection - * @param socket The BluetoothSocket on which the connection was made - * @param device The BluetoothDevice that has been connected - */ - public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) { - if (D) 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(AltosDroid.MESSAGE_DEVICE_NAME); - Bundle bundle = new Bundle(); - bundle.putString(AltosDroid.DEVICE_NAME, device.getName()); - msg.setData(bundle); - mHandler.sendMessage(msg); - - setState(STATE_CONNECTED); - } - - /** - * Stop all threads - */ - public synchronized void stop() { - if (D) Log.d(TAG, "stop"); - - if (mConnectThread != null) { - mConnectThread.cancel(); - mConnectThread = null; - } - - if (mConnectedThread != null) { - mConnectedThread.cancel(); - mConnectedThread = null; - } - - setState(STATE_NONE); - } - - /** - * Write to the ConnectedThread in an unsynchronized manner - * @param out The bytes to write - * @see ConnectedThread#write(byte[]) - */ - public void write(byte[] out) { - // Create temporary object - ConnectedThread r; - // Synchronize a copy of the ConnectedThread - synchronized (this) { - if (mState != STATE_CONNECTED) return; - r = mConnectedThread; - } - // Perform the write unsynchronized - r.write(out); - } - - /** - * Indicate that the connection attempt failed and notify the UI Activity. - */ - private void connectionFailed() { - // Send a failure message back to the Activity - Message msg = mHandler.obtainMessage(AltosDroid.MESSAGE_TOAST); - Bundle bundle = new Bundle(); - bundle.putString(AltosDroid.TOAST, "Unable to connect device"); - msg.setData(bundle); - mHandler.sendMessage(msg); - - // Start the service over to restart listening mode - BluetoothChatService.this.start(); - } - - /** - * 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(AltosDroid.MESSAGE_TOAST); - Bundle bundle = new Bundle(); - bundle.putString(AltosDroid.TOAST, "Device connection was lost"); - msg.setData(bundle); - mHandler.sendMessage(msg); - - // Start the service over to restart listening mode - BluetoothChatService.this.start(); - } - - - /** - * This thread runs while attempting to make an outgoing connection - * with a device. It runs straight through; the connection either - * succeeds or fails. - */ - private class ConnectThread extends Thread { - private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); - private final BluetoothSocket mmSocket; - private final BluetoothDevice mmDevice; - - public ConnectThread(BluetoothDevice device) { - mmDevice = device; - BluetoothSocket tmp = null; - - try { - tmp = mmDevice.createInsecureRfcommSocketToServiceRecord(SPP_UUID); - } catch (IOException e) { - e.printStackTrace(); - } - mmSocket = tmp; - } - - 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 connect socket failed", e); - } - } - } - - /** - * This thread runs during a connection with a remote device. - * It handles all incoming and outgoing transmissions. - */ - private class ConnectedThread extends Thread { - private final BluetoothSocket mmSocket; - private final InputStream mmInStream; - private final OutputStream mmOutStream; - - public ConnectedThread(BluetoothSocket socket) { - 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; - } - - public void run() { - Log.i(TAG, "BEGIN mConnectedThread"); - byte[] buffer = new byte[1024]; - int bytes; - - // Keep listening to the InputStream while connected - while (true) { - try { - // Read from the InputStream - bytes = mmInStream.read(buffer); - - // Send the obtained bytes to the UI Activity - mHandler.obtainMessage(AltosDroid.MESSAGE_READ, bytes, -1, buffer.clone()) - .sendToTarget(); - } catch (IOException e) { - Log.e(TAG, "disconnected", e); - connectionLost(); - break; - } - } - } - - /** - * Write to the connected OutStream. - * @param buffer The bytes to write - */ - public void write(byte[] buffer) { - try { - mmOutStream.write(buffer); - mmOutStream.write('\n'); - - // Share the sent message back to the UI Activity - mHandler.obtainMessage(AltosDroid.MESSAGE_WRITE, -1, -1, buffer) - .sendToTarget(); - } catch (IOException e) { - Log.e(TAG, "Exception during write", e); - } - } - - public void cancel() { - try { - mmSocket.close(); - } catch (IOException e) { - Log.e(TAG, "close() of connect socket failed", e); - } - } - } -} -- cgit v1.2.3 From 917f519a4e876087590a3a260fbbccf4c0ac3e31 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 14:54:06 +1200 Subject: altosdroid: remove UI components/imports no longer used Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 521588fb..a39dfa5d 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -26,16 +26,16 @@ import android.os.Handler; import android.os.Message; import android.text.method.ScrollingMovementMethod; import android.util.Log; -import android.view.KeyEvent; +//import android.view.KeyEvent; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.view.View; +//import android.view.View; import android.view.Window; -import android.view.View.OnClickListener; -import android.view.inputmethod.EditorInfo; -import android.widget.Button; -import android.widget.EditText; +//import android.view.View.OnClickListener; +//import android.view.inputmethod.EditorInfo; +//import android.widget.Button; +//import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import org.altusmetrum.AltosDroid.R; @@ -61,8 +61,6 @@ public class AltosDroid extends Activity { public static final String TOAST = "toast"; - private EditText mOutEditText; - private Button mSendButton; // Intent request codes private static final int REQUEST_CONNECT_DEVICE = 1; @@ -71,6 +69,8 @@ public class AltosDroid extends Activity { // Layout Views private TextView mTitle; private TextView mSerialView; + //private EditText mOutEditText; + //private Button mSendButton; // Name of the connected device private String mConnectedDeviceName = null; // Local Bluetooth adapter -- cgit v1.2.3 From 3f3da6626ef41b2cab116d6299d2a89cbf7718a9 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 14:54:54 +1200 Subject: altosdroid: Re-locate TextView initialisation Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index a39dfa5d..c18a73f8 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -93,6 +93,11 @@ public class AltosDroid extends Activity { mTitle.setText(R.string.app_name); mTitle = (TextView) findViewById(R.id.title_right_text); + mSerialView = (TextView) findViewById(R.id.in); + mSerialView.setMovementMethod(new ScrollingMovementMethod()); + mSerialView.setClickable(false); + mSerialView.setLongClickable(false); + // If the adapter is null, then Bluetooth is not supported if (mBluetoothAdapter == null) { Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show(); @@ -156,11 +161,6 @@ public class AltosDroid extends Activity { private void setupChat() { Log.d(TAG, "setupChat()"); - mSerialView = (TextView) findViewById(R.id.in); - mSerialView.setMovementMethod(new ScrollingMovementMethod()); - mSerialView.setClickable(false); - mSerialView.setLongClickable(false); - // Initialize the compose field with a listener for the return key mOutEditText = (EditText) findViewById(R.id.edit_text_out); mOutEditText.setOnEditorActionListener(mWriteListener); -- cgit v1.2.3 From cfe93315fc0e4b01a95b8e59f24aca96b5a66daf Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 14:55:19 +1200 Subject: altosdroid: whitespace Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index c18a73f8..5b48d571 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -86,8 +86,6 @@ public class AltosDroid extends Activity { setContentView(R.layout.main); getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title); - // Get local Bluetooth adapter - mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // Set up the custom title mTitle = (TextView) findViewById(R.id.title_left_text); mTitle.setText(R.string.app_name); @@ -98,6 +96,9 @@ public class AltosDroid extends Activity { mSerialView.setClickable(false); mSerialView.setLongClickable(false); + // Get local Bluetooth adapter + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + // If the adapter is null, then Bluetooth is not supported if (mBluetoothAdapter == null) { Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show(); -- cgit v1.2.3 From 95a34caa8343997bcf7d8969ee8ae3124efcb573 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 14:57:04 +1200 Subject: altosdroid: Remove AltosLib import from main thread --- altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java | 1 - 1 file changed, 1 deletion(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 5b48d571..8abc8a7b 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -39,7 +39,6 @@ import android.view.Window; import android.widget.TextView; import android.widget.Toast; import org.altusmetrum.AltosDroid.R; -import org.altusmetrum.AltosLib.*; /** * This is the main Activity that displays the current chat session. -- cgit v1.2.3 From ffdfc08c317f503e30604d058749b24c3ca7bafa Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:00:23 +1200 Subject: altosdroid: Add service start/bind/unbind to AltosDroid Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 8abc8a7b..54b61c67 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -21,9 +21,15 @@ import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.Intent; +import android.content.Context; +import android.content.ComponentName; +import android.content.ServiceConnection; +import android.os.IBinder; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; import android.text.method.ScrollingMovementMethod; import android.util.Log; //import android.view.KeyEvent; @@ -70,11 +76,30 @@ public class AltosDroid extends Activity { private TextView mSerialView; //private EditText mOutEditText; //private Button mSendButton; + + private boolean mIsBound; + Messenger mService = null; + // Name of the connected device private String mConnectedDeviceName = null; // Local Bluetooth adapter private BluetoothAdapter mBluetoothAdapter = null; + }; + + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + mService = new Messenger(service); + } + + public void onServiceDisconnected(ComponentName className) { + // This is called when the connection with the service has been unexpectedly disconnected - process crashed. + mService = null; + } + }; + + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -105,6 +130,10 @@ public class AltosDroid extends Activity { return; } + // Start Telemetry Service + startService(new Intent(AltosDroid.this, TelemetryService.class)); + + doBindService(); } @Override @@ -152,6 +181,9 @@ public class AltosDroid extends Activity { @Override public void onDestroy() { super.onDestroy(); + + doUnbindService(); + if(D) Log.e(TAG, "--- ON DESTROY ---"); } @@ -277,4 +309,19 @@ public class AltosDroid extends Activity { return false; } + + void doBindService() { + bindService(new Intent(this, TelemetryService.class), mConnection, Context.BIND_AUTO_CREATE); + mIsBound = true; + } + + void doUnbindService() { + if (mIsBound) { + // If we have received the service, and hence registered with it, then now is the time to unregister. + // Detach our existing connection. + unbindService(mConnection); + mIsBound = false; + } + } + } -- cgit v1.2.3 From c9689a3ef65ea9da5a7009834add789737ffb6a9 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:03:54 +1200 Subject: altosdroid: Clean up imports in TelemetryService * Begin adding AltosLib usage Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/TelemetryService.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 95b655c2..7d0f7a70 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -29,12 +29,15 @@ import android.widget.Toast; // Need the following import to get access to the app resources, since this // class is in a sub-package. -import org.altusmetrum.AltosDroid.R; - +//import org.altusmetrum.AltosDroid.R; +import org.altusmetrum.AltosLib.*; public class TelemetryService extends Service { + private static final String TAG = "TelemetryService"; + private static final boolean D = true; + /** * Class for clients to access. Because we know this service always * runs in the same process as its clients, we don't need to deal with @@ -50,6 +53,13 @@ public class TelemetryService extends Service { private int NOTIFICATION = R.string.telemetry_service_label; private NotificationManager mNM; + + // Name of the connected device + private String mConnectedDeviceName = null; + private AltosBluetooth mAltosBluetooth = null; + + LinkedBlockingQueue telem; + @Override public void onCreate() { // Create a reference to the NotificationManager so that we can update our notifcation text later -- cgit v1.2.3 From bad155538c4630c62ade80afd20830aad37c287e Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:10:15 +1200 Subject: altosdroid: AltosBluetooth.java * Clean up imports * Convert from reflection to using Well Known UUID for SPP. * clean up local variables * Add debug conditionals to logging * remove references to socket type Signed-off-by: Mike Beattie --- .../org/altusmetrum/AltosDroid/AltosBluetooth.java | 58 ++++++++-------------- 1 file changed, 21 insertions(+), 37 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index 390dccdb..1f094679 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -21,14 +21,11 @@ package org.altusmetrum.AltosDroid; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.lang.reflect.Method; +import java.util.UUID; + import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; -import android.content.Context; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.util.Log; import org.altusmetrum.AltosLib.*; @@ -52,35 +49,22 @@ public class AltosBluetooth extends AltosLink { private OutputStream output; private class ConnectThread extends Thread { - private final BluetoothDevice mmDevice; - private String mSocketType; - BluetoothSocket tmp_socket; + private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); - public ConnectThread(BluetoothDevice device, boolean secure) { - mmDevice = device; - mSocketType = secure ? "Secure" : "Insecure"; + public ConnectThread(BluetoothDevice device) { + BluetoothSocket tmp_socket = null; - // Get a BluetoothSocket for a connection with the - // given BluetoothDevice try { - if (secure) { - Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}); - tmp_socket = (BluetoothSocket) m.invoke(device, 2); - // tmp = device.createRfcommSocket(2); - } else { - Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class}); - tmp_socket = (BluetoothSocket) m.invoke(device, 2); - // tmp = device.createInsecureRfcommSocket(2); - } - } catch (Exception e) { - Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e); + tmp_socket = device.createInsecureRfcommSocketToServiceRecord(SPP_UUID); + } catch (IOException e) { e.printStackTrace(); } + socket = tmp_socket; } public void run() { - Log.i(TAG, "BEGIN connect_thread SocketType:" + mSocketType); - setName("ConnectThread" + mSocketType); + if (D) Log.i(TAG, "BEGIN ConnectThread"); + setName("ConnectThread"); // Always cancel discovery because it will slow down a connection adapter.cancelDiscovery(); @@ -89,14 +73,13 @@ public class AltosBluetooth extends AltosLink { try { // This is a blocking call and will only return on a // successful connection or an exception - tmp_socket.connect(); + socket.connect(); } catch (IOException e) { // Close the socket try { - tmp_socket.close(); + socket.close(); } catch (IOException e2) { - Log.e(TAG, "unable to close() " + mSocketType + - " socket during connection failure", e2); + if (D) Log.e(TAG, "unable to close() socket during connection failure", e2); } connection_failed(); return; @@ -104,25 +87,26 @@ public class AltosBluetooth extends AltosLink { try { synchronized (AltosBluetooth.this) { - input = tmp_socket.getInputStream(); - output = tmp_socket.getOutputStream(); - socket = tmp_socket; + input = socket.getInputStream(); + output = socket.getOutputStream(); + // Reset the ConnectThread because we're done AltosBluetooth.this.notify(); connect_thread = null; + if (D) Log.i(TAG, "Completed connect"); } } catch (Exception e) { - Log.e(TAG, "Failed to finish connection", e); + if (D) Log.e(TAG, "Failed to finish connection", e); e.printStackTrace(); } } public void cancel() { try { - if (tmp_socket != null) - tmp_socket.close(); + if (socket != null) + socket.close(); } catch (IOException e) { - Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e); + if (D) Log.e(TAG, "close() of connect socket failed", e); } } } -- cgit v1.2.3 From d184638be79dafd6fb43df21040eb52402f54ea5 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:11:12 +1200 Subject: altosdroid: AltosBluetooth.java * clean up variables/comments Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/AltosBluetooth.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index 1f094679..4c1f09a2 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -36,17 +36,13 @@ public class AltosBluetooth extends AltosLink { private static final String TAG = "AltosBluetooth"; private static final boolean D = true; - /** - * This thread runs while attempting to make an outgoing connection - * with a device. It runs straight through; the connection either - * succeeds or fails. - */ - - private BluetoothAdapter adapter; - private ConnectThread connect_thread; - private BluetoothSocket socket; - private InputStream input; - private OutputStream output; + private ConnectThread connect_thread = null; + + private BluetoothAdapter adapter; + private BluetoothDevice device; + private BluetoothSocket socket; + private InputStream input; + private OutputStream output; private class ConnectThread extends Thread { private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); -- cgit v1.2.3 From b59e7d0b201290f2cb0fd494ef28c1402e11ba3b Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:18:44 +1200 Subject: altosdroid: clean up stub functions in AltosBluetooth.java Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/AltosBluetooth.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index 4c1f09a2..79e31e89 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -149,20 +149,12 @@ public class AltosBluetooth extends AltosLink { } } - public void flush_output() { - super.flush_output(); - /* any local work needed to flush bluetooth? */ - } - public boolean can_cancel_reply() { - return false; - } - public boolean show_reply_timeout() { - return true; - } - - public void hide_reply_timeout() { - } + //public void flush_output() { super.flush_output(); } + + public boolean can_cancel_reply() { return false; } + public boolean show_reply_timeout() { return true; } + public void hide_reply_timeout() { } public AltosBluetooth(BluetoothDevice device) { adapter = BluetoothAdapter.getDefaultAdapter(); -- cgit v1.2.3 From 5ce132b3366cd120499fcbe22b5fbe96d21b8584 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:20:42 +1200 Subject: altosdroid: Move constructor for AltosBluetooth Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/AltosBluetooth.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index 79e31e89..32140b3c 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -44,6 +44,15 @@ public class AltosBluetooth extends AltosLink { private InputStream input; private OutputStream output; + // Constructor + public AltosBluetooth(BluetoothDevice in_device) { + adapter = BluetoothAdapter.getDefaultAdapter(); + + + connect_thread = new ConnectThread(device); + connect_thread.start(); + } + private class ConnectThread extends Thread { private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); @@ -156,9 +165,4 @@ public class AltosBluetooth extends AltosLink { public boolean show_reply_timeout() { return true; } public void hide_reply_timeout() { } - public AltosBluetooth(BluetoothDevice device) { - adapter = BluetoothAdapter.getDefaultAdapter(); - connect_thread = new ConnectThread(device, true); - connect_thread.start(); - } -} \ No newline at end of file +} -- cgit v1.2.3 From fb8cd14cca61ca59b95c23e71505607b4509d4ed Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:21:36 +1200 Subject: altosdroid: Add input thread for reading from TBT Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index 32140b3c..4c3f979d 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -37,6 +37,7 @@ public class AltosBluetooth extends AltosLink { private static final boolean D = true; private ConnectThread connect_thread = null; + private Thread input_thread = null; private BluetoothAdapter adapter; private BluetoothDevice device; @@ -51,6 +52,9 @@ public class AltosBluetooth extends AltosLink { connect_thread = new ConnectThread(device); connect_thread.start(); + + input_thread = new Thread(this); + input_thread.start(); } private class ConnectThread extends Thread { @@ -155,6 +159,13 @@ public class AltosBluetooth extends AltosLink { connect_thread.cancel(); connect_thread = null; } + if (input_thread != null) { + try { + input_thread.interrupt(); + input_thread.join(); + } catch (Exception e) {} + input_thread = null; + } } } -- cgit v1.2.3 From ef29a197ce3318404f37e8a0b24d235e8b024a1f Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:21:57 +1200 Subject: altosdroid: Add debugging statements to AltosBluetooth Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index 4c3f979d..db63b342 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -127,13 +127,16 @@ public class AltosBluetooth extends AltosLink { } private void connection_failed() { + if (D) Log.i(TAG, "Bluetooth Connection failed!"); } public void print(String data) { byte[] bytes = data.getBytes(); try { + if (D) Log.i(TAG, "Entering print();"); wait_connected(); output.write(bytes); + if (D) Log.i(TAG, "Writing bytes: '" + data + "'"); } catch (IOException e) { connection_failed(); } catch (InterruptedException e) { -- cgit v1.2.3 From bcd53483ccf4bbb2f163a011faae6d19a7bbed0d Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:22:23 +1200 Subject: altosdroid: Add TBT initialisation to AltosBluetooth Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index db63b342..6b86a153 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -99,6 +99,10 @@ public class AltosBluetooth extends AltosLink { input = socket.getInputStream(); output = socket.getOutputStream(); + // Configure the newly connected device for telemetry + print("~\nE 0\n"); + set_monitor(false); + // Reset the ConnectThread because we're done AltosBluetooth.this.notify(); connect_thread = null; -- cgit v1.2.3 From b69796991c1da6baf245349fcc4392668b9b5570 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:23:17 +1200 Subject: altosdroid: begin adding IPC to main thread Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 87 +++++++++++++++++++--- 1 file changed, 76 insertions(+), 11 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 54b61c67..c1b9c654 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -54,18 +54,15 @@ public class AltosDroid extends Activity { private static final String TAG = "AltosDroid"; private static final boolean D = true; - // 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; - - // Key names received from the BluetoothChatService Handler - public static final String DEVICE_NAME = "device_name"; - public static final String TOAST = "toast"; - + // Message types sent from the TelemetryService Handler + public static final int MSG_STATE_CHANGE = 1; + public static final int MSG_DEVNAME = 2; + public static final int MSG_INCOMING_TELEM = 3; + public static final int MSG_TOAST = 4; + // Key names received from the TelemetryService Handler + public static final String KEY_DEVNAME = "key_devname"; + public static final String KEY_TOAST = "key_toast"; // Intent request codes private static final int REQUEST_CONNECT_DEVICE = 1; @@ -79,18 +76,69 @@ public class AltosDroid extends Activity { private boolean mIsBound; Messenger mService = null; + final Messenger mMessenger = new Messenger(new IncomingHandler()); // Name of the connected device private String mConnectedDeviceName = null; // Local Bluetooth adapter private BluetoothAdapter mBluetoothAdapter = null; + + // The Handler that gets information back from the Telemetry Service + class IncomingHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_STATE_CHANGE: + if(D) Log.i(TAG, "MSG_STATE_CHANGE: " + msg.arg1); + switch (msg.arg1) { + case TelemetryService.STATE_CONNECTED: + mTitle.setText(R.string.title_connected_to); + mTitle.append(mConnectedDeviceName); + mSerialView.setText(""); + break; + case TelemetryService.STATE_CONNECTING: + mTitle.setText(R.string.title_connecting); + break; + case TelemetryService.STATE_READY: + case TelemetryService.STATE_NONE: + mTitle.setText(R.string.title_not_connected); + break; + } + break; + case MSG_INCOMING_TELEM: + byte[] buf = (byte[]) msg.obj; + // construct a string from the buffer + String telem = new String(buf); + mSerialView.append(telem); + break; + case MSG_DEVNAME: + // save the connected device's name + mConnectedDeviceName = msg.getData().getString(KEY_DEVNAME); + Toast.makeText(getApplicationContext(), "Connected to " + + mConnectedDeviceName, Toast.LENGTH_SHORT).show(); + break; + case MSG_TOAST: + Toast.makeText( + getApplicationContext(), + msg.getData().getString(KEY_TOAST), + Toast.LENGTH_SHORT).show(); + break; + } + } }; private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mService = new Messenger(service); + try { + Message msg = Message.obtain(null, TelemetryService.MSG_REGISTER_CLIENT); + msg.replyTo = mMessenger; + mService.send(msg); + } catch (RemoteException e) { + // In this case the service has crashed before we could even do anything with it + } } public void onServiceDisconnected(ComponentName className) { @@ -286,6 +334,14 @@ public class AltosDroid extends Activity { // Get the BLuetoothDevice object BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); // Attempt to connect to the device + try { + //Message msg = Message.obtain(null, TelemetryService.MSG_CONNECT_TELEBT); + //msg.obj = device; + //mService.send(msg); + mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT_TELEBT, device)); + } catch (RemoteException e) { + e.printStackTrace(); + } } @@ -318,6 +374,15 @@ public class AltosDroid extends Activity { void doUnbindService() { if (mIsBound) { // If we have received the service, and hence registered with it, then now is the time to unregister. + if (mService != null) { + try { + Message msg = Message.obtain(null, TelemetryService.MSG_UNREGISTER_CLIENT); + msg.replyTo = mMessenger; + mService.send(msg); + } catch (RemoteException e) { + // There is nothing special we need to do if the service has crashed. + } + } // Detach our existing connection. unbindService(mConnection); mIsBound = false; -- cgit v1.2.3 From a33333b97e810f50db36f345aab71a3200feccc3 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:24:19 +1200 Subject: altosdroid: remove old Binder from TelemetryService Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/TelemetryService.java | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 7d0f7a70..15293b9e 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -22,7 +22,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; -import android.os.Binder; +//import android.os.Binder; import android.os.IBinder; import android.util.Log; import android.widget.Toast; @@ -38,16 +38,6 @@ public class TelemetryService extends Service { private static final String TAG = "TelemetryService"; private static final boolean D = true; - /** - * Class for clients to access. Because we know this service always - * runs in the same process as its clients, we don't need to deal with - * IPC. - */ - public class TelemetryBinder extends Binder { - TelemetryService getService() { - return TelemetryService.this; - } - } // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. private int NOTIFICATION = R.string.telemetry_service_label; @@ -106,11 +96,7 @@ public class TelemetryService extends Service { @Override public IBinder onBind(Intent intent) { - return mBinder; } - // This is the object that receives interactions from clients. See - // RemoteService for a more complete example. - private final IBinder mBinder = new TelemetryBinder(); } -- cgit v1.2.3 From 6ffcc82d8d18d3f05d4f5881e50dda298b43c114 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:28:09 +1200 Subject: altosdroid: begin adding IPC to TelemetryService * And add imports for LinkedBlockingQueue... oops! Signed-off-by: Mike Beattie --- .../altusmetrum/AltosDroid/TelemetryService.java | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 15293b9e..337aece1 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -17,13 +17,20 @@ package org.altusmetrum.AltosDroid; +import java.util.ArrayList; +import java.util.concurrent.LinkedBlockingQueue; + import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; +import android.bluetooth.BluetoothDevice; import android.content.Intent; //import android.os.Binder; import android.os.IBinder; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; import android.util.Log; import android.widget.Toast; @@ -38,11 +45,17 @@ public class TelemetryService extends Service { private static final String TAG = "TelemetryService"; private static final boolean D = true; + static final int MSG_REGISTER_CLIENT = 1; + static final int MSG_UNREGISTER_CLIENT = 2; + static final int MSG_CONNECT_TELEBT = 3; + // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. private int NOTIFICATION = R.string.telemetry_service_label; private NotificationManager mNM; + ArrayList mClients = new ArrayList(); // Keeps track of all current registered clients. + final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler. // Name of the connected device private String mConnectedDeviceName = null; @@ -50,6 +63,43 @@ public class TelemetryService extends Service { LinkedBlockingQueue telem; + // Handler of incoming messages from clients. + class IncomingHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_REGISTER_CLIENT: + mClients.add(msg.replyTo); + if (D) Log.d(TAG, "Client bound to service"); + break; + case MSG_UNREGISTER_CLIENT: + mClients.remove(msg.replyTo); + if (D) Log.d(TAG, "Client unbound from service"); + break; + case MSG_CONNECT_TELEBT: + if (D) Log.d(TAG, "Connect command received"); + TeleBT_stop(); + TeleBT_start((BluetoothDevice) msg.obj); + break; + default: + super.handleMessage(msg); + } + } + } + + private void TeleBT_stop() { + if (mAltosBluetooth != null) { + mAltosBluetooth.close(); + mAltosBluetooth = null; + } + telem.clear(); + } + + private void TeleBT_start(BluetoothDevice d) { + mAltosBluetooth = new AltosBluetooth(d); + mAltosBluetooth.add_monitor(telem); + } + @Override public void onCreate() { // Create a reference to the NotificationManager so that we can update our notifcation text later @@ -86,6 +136,8 @@ public class TelemetryService extends Service { @Override public void onDestroy() { + // Stop the bluetooth Comms threads + TeleBT_stop(); // Demote us from the foreground, and cancel the persistent notification. stopForeground(true); @@ -96,6 +148,7 @@ public class TelemetryService extends Service { @Override public IBinder onBind(Intent intent) { + return mMessenger.getBinder(); } -- cgit v1.2.3 From 5f4c47389a3d0d10d659a2e00fc74a150b5fed88 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:28:36 +1200 Subject: altosdroid: Add State constants for future usage Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 337aece1..9059ca79 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -49,6 +49,11 @@ public class TelemetryService extends Service { static final int MSG_UNREGISTER_CLIENT = 2; static final int MSG_CONNECT_TELEBT = 3; + public static final int STATE_NONE = 0; + public static final int STATE_READY = 1; + public static final int STATE_CONNECTING = 2; + public static final int STATE_CONNECTED = 3; + // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. private int NOTIFICATION = R.string.telemetry_service_label; -- cgit v1.2.3 From bf7def1a7b93867dfe16fe6499ee028747634c41 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 15:28:58 +1200 Subject: altosdroid: Remove Binder import from TelemetryService Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java | 1 - 1 file changed, 1 deletion(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 9059ca79..2ee7fe58 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -26,7 +26,6 @@ import android.app.PendingIntent; import android.app.Service; import android.bluetooth.BluetoothDevice; import android.content.Intent; -//import android.os.Binder; import android.os.IBinder; import android.os.Handler; import android.os.Message; -- cgit v1.2.3 From 54baecc208a40606e3242b2cbd5e66567053646f Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:12:48 +1200 Subject: altosdroid: Convert handlers to use weakreferences * Also renamed bluetooth start/stop methods Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 27 +++++++++++++--------- .../altusmetrum/AltosDroid/TelemetryService.java | 20 +++++++++------- 2 files changed, 28 insertions(+), 19 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index c1b9c654..d23d504f 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -17,6 +17,7 @@ package org.altusmetrum.AltosDroid; +import java.lang.ref.WeakReference; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; @@ -85,24 +86,28 @@ public class AltosDroid extends Activity { // The Handler that gets information back from the Telemetry Service - class IncomingHandler extends Handler { + static class IncomingHandler extends Handler { + private final WeakReference mAltosDroid; + IncomingHandler(AltosDroid ad) { mAltosDroid = new WeakReference(ad); } + @Override public void handleMessage(Message msg) { + AltosDroid ad = mAltosDroid.get(); switch (msg.what) { case MSG_STATE_CHANGE: if(D) Log.i(TAG, "MSG_STATE_CHANGE: " + msg.arg1); switch (msg.arg1) { case TelemetryService.STATE_CONNECTED: - mTitle.setText(R.string.title_connected_to); - mTitle.append(mConnectedDeviceName); - mSerialView.setText(""); + ad.mTitle.setText(R.string.title_connected_to); + ad.mTitle.append(ad.mConnectedDeviceName); + ad.mSerialView.setText(""); break; case TelemetryService.STATE_CONNECTING: - mTitle.setText(R.string.title_connecting); + ad.mTitle.setText(R.string.title_connecting); break; case TelemetryService.STATE_READY: case TelemetryService.STATE_NONE: - mTitle.setText(R.string.title_not_connected); + ad.mTitle.setText(R.string.title_not_connected); break; } break; @@ -110,17 +115,17 @@ public class AltosDroid extends Activity { byte[] buf = (byte[]) msg.obj; // construct a string from the buffer String telem = new String(buf); - mSerialView.append(telem); + ad.mSerialView.append(telem); break; case MSG_DEVNAME: // save the connected device's name - mConnectedDeviceName = msg.getData().getString(KEY_DEVNAME); - Toast.makeText(getApplicationContext(), "Connected to " - + mConnectedDeviceName, Toast.LENGTH_SHORT).show(); + ad.mConnectedDeviceName = msg.getData().getString(KEY_DEVNAME); + Toast.makeText(ad.getApplicationContext(), "Connected to " + + ad.mConnectedDeviceName, Toast.LENGTH_SHORT).show(); break; case MSG_TOAST: Toast.makeText( - getApplicationContext(), + ad.getApplicationContext(), msg.getData().getString(KEY_TOAST), Toast.LENGTH_SHORT).show(); break; diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 2ee7fe58..1c0e94b3 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -17,6 +17,7 @@ package org.altusmetrum.AltosDroid; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.concurrent.LinkedBlockingQueue; @@ -68,22 +69,25 @@ public class TelemetryService extends Service { LinkedBlockingQueue telem; // Handler of incoming messages from clients. - class IncomingHandler extends Handler { + static class IncomingHandler extends Handler { + private final WeakReference service; + IncomingHandler(TelemetryService s) { service = new WeakReference(s); } + @Override public void handleMessage(Message msg) { + TelemetryService s = service.get(); switch (msg.what) { case MSG_REGISTER_CLIENT: - mClients.add(msg.replyTo); + s.mClients.add(msg.replyTo); if (D) Log.d(TAG, "Client bound to service"); break; case MSG_UNREGISTER_CLIENT: - mClients.remove(msg.replyTo); + s.mClients.remove(msg.replyTo); if (D) Log.d(TAG, "Client unbound from service"); break; case MSG_CONNECT_TELEBT: if (D) Log.d(TAG, "Connect command received"); - TeleBT_stop(); - TeleBT_start((BluetoothDevice) msg.obj); + s.startAltosBluetooth((BluetoothDevice) msg.obj); break; default: super.handleMessage(msg); @@ -91,7 +95,7 @@ public class TelemetryService extends Service { } } - private void TeleBT_stop() { + private void stopAltosBluetooth() { if (mAltosBluetooth != null) { mAltosBluetooth.close(); mAltosBluetooth = null; @@ -99,7 +103,7 @@ public class TelemetryService extends Service { telem.clear(); } - private void TeleBT_start(BluetoothDevice d) { + private void startAltosBluetooth(BluetoothDevice d) { mAltosBluetooth = new AltosBluetooth(d); mAltosBluetooth.add_monitor(telem); } @@ -141,7 +145,7 @@ public class TelemetryService extends Service { public void onDestroy() { // Stop the bluetooth Comms threads - TeleBT_stop(); + stopAltosBluetooth(); // Demote us from the foreground, and cancel the persistent notification. stopForeground(true); -- cgit v1.2.3 From 21359f600354e8ee840e839e61ef97d30f3586fc Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:13:33 +1200 Subject: altosdroid: disable NotificationManager stuff for now Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 1c0e94b3..60500a2c 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -22,7 +22,7 @@ import java.util.ArrayList; import java.util.concurrent.LinkedBlockingQueue; import android.app.Notification; -import android.app.NotificationManager; +//import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.bluetooth.BluetoothDevice; @@ -57,7 +57,7 @@ public class TelemetryService extends Service { // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. private int NOTIFICATION = R.string.telemetry_service_label; - private NotificationManager mNM; + //private NotificationManager mNM; ArrayList mClients = new ArrayList(); // Keeps track of all current registered clients. final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler. @@ -111,7 +111,7 @@ public class TelemetryService extends Service { @Override public void onCreate() { // Create a reference to the NotificationManager so that we can update our notifcation text later - mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + //mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); } @Override -- cgit v1.2.3 From a6373e84393312ed0fbf22285c704819c2011588 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:14:09 +1200 Subject: altosdroid: init telem blocking list.. oops! Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 60500a2c..89c45d6c 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -112,6 +112,8 @@ public class TelemetryService extends Service { public void onCreate() { // Create a reference to the NotificationManager so that we can update our notifcation text later //mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + + telem = new LinkedBlockingQueue(); } @Override -- cgit v1.2.3 From 2c5513c51b187ad26a59b193b401f38c35141d27 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:16:04 +1200 Subject: altosdroid: Rename Connect message, add connected message Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 89c45d6c..cf7ae6da 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -47,7 +47,8 @@ public class TelemetryService extends Service { static final int MSG_REGISTER_CLIENT = 1; static final int MSG_UNREGISTER_CLIENT = 2; - static final int MSG_CONNECT_TELEBT = 3; + static final int MSG_CONNECT = 3; + static final int MSG_CONNECTED = 4; public static final int STATE_NONE = 0; public static final int STATE_READY = 1; @@ -85,10 +86,13 @@ public class TelemetryService extends Service { s.mClients.remove(msg.replyTo); if (D) Log.d(TAG, "Client unbound from service"); break; - case MSG_CONNECT_TELEBT: + case MSG_CONNECT: if (D) Log.d(TAG, "Connect command received"); s.startAltosBluetooth((BluetoothDevice) msg.obj); break; + case MSG_CONNECTED: + if (D) Log.d(TAG, "Connected to device"); + break; default: super.handleMessage(msg); } -- cgit v1.2.3 From fe6680dd3b4c31b3d4edc3f06a142f02bcb879df Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:16:49 +1200 Subject: altosdroid: init device variable... oops! Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index 6b86a153..c16e3cf5 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -48,7 +48,7 @@ public class AltosBluetooth extends AltosLink { // Constructor public AltosBluetooth(BluetoothDevice in_device) { adapter = BluetoothAdapter.getDefaultAdapter(); - + device = in_device; connect_thread = new ConnectThread(device); connect_thread.start(); -- cgit v1.2.3 From 215d78f06093bd8a8b08a85cae0f1f34aee2a6ec Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:19:06 +1200 Subject: altosdroid: begin adding state support Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/TelemetryService.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index cf7ae6da..6a23dca3 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -66,7 +66,7 @@ public class TelemetryService extends Service { // Name of the connected device private String mConnectedDeviceName = null; private AltosBluetooth mAltosBluetooth = null; - + private int state = STATE_NONE; LinkedBlockingQueue telem; // Handler of incoming messages from clients. @@ -92,6 +92,7 @@ public class TelemetryService extends Service { break; case MSG_CONNECTED: if (D) Log.d(TAG, "Connected to device"); + s.setState(STATE_CONNECTED); break; default: super.handleMessage(msg); @@ -100,6 +101,7 @@ public class TelemetryService extends Service { } private void stopAltosBluetooth() { + setState(STATE_READY); if (mAltosBluetooth != null) { mAltosBluetooth.close(); mAltosBluetooth = null; @@ -110,6 +112,14 @@ public class TelemetryService extends Service { private void startAltosBluetooth(BluetoothDevice d) { mAltosBluetooth = new AltosBluetooth(d); mAltosBluetooth.add_monitor(telem); + setState(STATE_CONNECTING); + } + + private synchronized void setState(int s) { + if (D) Log.d(TAG, "setState() " + state + " -> " + s); + state = s; + + sendMessageToClients(Message.obtain(null, AltosDroid.MSG_STATE_CHANGE, state, -1)); } @Override @@ -118,6 +128,7 @@ public class TelemetryService extends Service { //mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); telem = new LinkedBlockingQueue(); + setState(STATE_READY); } @Override -- cgit v1.2.3 From d7173e814c49826f39bba1ff6b024819c555860c Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:20:01 +1200 Subject: altosdroid: reflect change in message name Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index d23d504f..b8ddd574 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -343,7 +343,7 @@ public class AltosDroid extends Activity { //Message msg = Message.obtain(null, TelemetryService.MSG_CONNECT_TELEBT); //msg.obj = device; //mService.send(msg); - mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT_TELEBT, device)); + mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT, device)); } catch (RemoteException e) { e.printStackTrace(); } -- cgit v1.2.3 From a9ec3c96288b7ea4e40586321a0a98edf0c8fee5 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:23:33 +1200 Subject: altosdroid: Need access to handler inside AltosBluetooth * Also move add_monitor() call Signed-off-by: Mike Beattie --- altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java | 6 +++++- altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java | 7 ++++--- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index c16e3cf5..3bfa3488 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -26,6 +26,7 @@ import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; +import android.os.Handler; import android.util.Log; import org.altusmetrum.AltosLib.*; @@ -39,6 +40,8 @@ public class AltosBluetooth extends AltosLink { private ConnectThread connect_thread = null; private Thread input_thread = null; + private Handler handler; + private BluetoothAdapter adapter; private BluetoothDevice device; private BluetoothSocket socket; @@ -46,9 +49,10 @@ public class AltosBluetooth extends AltosLink { private OutputStream output; // Constructor - public AltosBluetooth(BluetoothDevice in_device) { + public AltosBluetooth(BluetoothDevice in_device, Handler in_handler) { adapter = BluetoothAdapter.getDefaultAdapter(); device = in_device; + handler = in_handler; connect_thread = new ConnectThread(device); connect_thread.start(); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 6a23dca3..1903cc1d 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -61,7 +61,8 @@ public class TelemetryService extends Service { //private NotificationManager mNM; ArrayList mClients = new ArrayList(); // Keeps track of all current registered clients. - final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler. + final Handler mHandler = new IncomingHandler(this); + final Messenger mMessenger = new Messenger(mHandler); // Target we publish for clients to send messages to IncomingHandler. // Name of the connected device private String mConnectedDeviceName = null; @@ -93,6 +94,7 @@ public class TelemetryService extends Service { case MSG_CONNECTED: if (D) Log.d(TAG, "Connected to device"); s.setState(STATE_CONNECTED); + s.mAltosBluetooth.add_monitor(s.telem); break; default: super.handleMessage(msg); @@ -110,8 +112,7 @@ public class TelemetryService extends Service { } private void startAltosBluetooth(BluetoothDevice d) { - mAltosBluetooth = new AltosBluetooth(d); - mAltosBluetooth.add_monitor(telem); + mAltosBluetooth = new AltosBluetooth(d, mHandler); setState(STATE_CONNECTING); } -- cgit v1.2.3 From 31bffa435cec2098c7ab5c42c829ba6e1578b5d2 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:24:13 +1200 Subject: altosdroid: need sendMessageToClients() for setState().. oops! Signed-off-by: Mike Beattie --- .../src/org/altusmetrum/AltosDroid/TelemetryService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 1903cc1d..9c2fde97 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -102,6 +102,16 @@ public class TelemetryService extends Service { } } + private void sendMessageToClients(Message m) { + for (int i=mClients.size()-1; i>=0; i--) { + try { + mClients.get(i).send(m); + } catch (RemoteException e) { + mClients.remove(i); + } + } + } + private void stopAltosBluetooth() { setState(STATE_READY); if (mAltosBluetooth != null) { -- cgit v1.2.3 From 3d6fc5fe462531e05ca4b9be1a421490e067a28b Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:26:58 +1200 Subject: altosdroid: lots of debugging statements Signed-off-by: Mike Beattie --- .../org/altusmetrum/AltosDroid/AltosBluetooth.java | 22 +++++++++++++++++----- .../altusmetrum/AltosDroid/TelemetryService.java | 3 +++ 2 files changed, 20 insertions(+), 5 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index 3bfa3488..3071c8f1 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -76,7 +76,7 @@ public class AltosBluetooth extends AltosLink { } public void run() { - if (D) Log.i(TAG, "BEGIN ConnectThread"); + if (D) Log.i(TAG, "ConnectThread: BEGIN"); setName("ConnectThread"); // Always cancel discovery because it will slow down a connection @@ -123,28 +123,31 @@ public class AltosBluetooth extends AltosLink { if (socket != null) socket.close(); } catch (IOException e) { - if (D) Log.e(TAG, "close() of connect socket failed", e); + if (D) Log.e(TAG, "ConnectThread: close() of connect socket failed", e); } } } private synchronized void wait_connected() throws InterruptedException { + if (D) Log.i(TAG, "wait_connected(): begin"); if (input == null) { + if (D) Log.i(TAG, "wait_connected(): waiting"); wait(); + if (D) Log.i(TAG, "wait_connected(): wait ended.."); } } private void connection_failed() { - if (D) Log.i(TAG, "Bluetooth Connection failed!"); + if (D) Log.e(TAG, "Bluetooth Socket IO failed!"); } public void print(String data) { byte[] bytes = data.getBytes(); + if (D) Log.i(TAG, "print(): begin"); try { - if (D) Log.i(TAG, "Entering print();"); wait_connected(); output.write(bytes); - if (D) Log.i(TAG, "Writing bytes: '" + data + "'"); + if (D) Log.i(TAG, "print(): Wrote bytes: '" + data.replace('\n', '\\') + "'"); } catch (IOException e) { connection_failed(); } catch (InterruptedException e) { @@ -153,8 +156,10 @@ public class AltosBluetooth extends AltosLink { } public int getchar() { + if (D) Log.i(TAG, "getchar(): begin"); try { wait_connected(); + if (D) Log.i(TAG, "getchar(): proceeding"); return input.read(); } catch (IOException e) { connection_failed(); @@ -165,14 +170,21 @@ public class AltosBluetooth extends AltosLink { } public void close() { + if (D) Log.i(TAG, "close(): begin"); synchronized(this) { + if (D) Log.i(TAG, "close(): synched"); + if (connect_thread != null) { + if (D) Log.i(TAG, "close(): stopping connect_thread"); connect_thread.cancel(); connect_thread = null; } if (input_thread != null) { + if (D) Log.i(TAG, "close(): stopping input_thread"); try { + if (D) Log.i(TAG, "close(): input_thread.interrupt()....."); input_thread.interrupt(); + if (D) Log.i(TAG, "close(): input_thread.join()....."); input_thread.join(); } catch (Exception e) {} input_thread = null; diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 9c2fde97..a61a1eda 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -113,8 +113,10 @@ public class TelemetryService extends Service { } private void stopAltosBluetooth() { + if (D) Log.i(TAG, "Stopping BT"); setState(STATE_READY); if (mAltosBluetooth != null) { + if (D) Log.i(TAG, "Closing AltosBluetooth"); mAltosBluetooth.close(); mAltosBluetooth = null; } @@ -122,6 +124,7 @@ public class TelemetryService extends Service { } private void startAltosBluetooth(BluetoothDevice d) { + if (D) Log.i(TAG, "Connecting to " + d.getName()); mAltosBluetooth = new AltosBluetooth(d, mHandler); setState(STATE_CONNECTING); } -- cgit v1.2.3 From d40f96fcc961cfbf6af67fc84591d2660d065ca0 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Sun, 26 Aug 2012 23:28:26 +1200 Subject: altosdroid: Strings and Layout changes Signed-off-by: Mike Beattie --- altosdroid/res/layout/main.xml | 22 +--------------------- altosdroid/res/values/strings.xml | 12 +++++------- .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 2 +- 3 files changed, 7 insertions(+), 29 deletions(-) (limited to 'altosdroid/src') diff --git a/altosdroid/res/layout/main.xml b/altosdroid/res/layout/main.xml index 070928a5..00ca63c8 100644 --- a/altosdroid/res/layout/main.xml +++ b/altosdroid/res/layout/main.xml @@ -23,31 +23,11 @@ - - - - -