I'm currently working on writing an App on Android to interface with an Arduino Board. I am able to send serial data to my Arduino just fine, however my app crashes at start up the moment I begin trying to receive data.
I currently have it set so a text field takes data from a user, and sends to the Arduino, Arduino does a function.
For my receive, I am making a new thread at start up to constantly listen for data from the Arduino. whenever the code in this thread is executed, it crashes.
I am using this library as my basis: https://github.com/mik3y/usb-serial-for-android
Below is the all the code pertinent, omitted code for other functionality this app is providing, that are unrealted:
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import android.hardware.usb.UsbManager;
import android.content.Intent;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.content.Context;
import android.util.Log;
import com.hoho.android.usbserial.driver.UsbSerialProber;
public class MainActivity extends Activity implements SensorEventListener, LocationListener{
private EditText sendTextField;
TextView uartRX;
public Handler Handler;
UsbManager manager;
/** Called to create application activity*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uartRX = (TextView)findViewById(R.id.rxUART);
sendTextField = (EditText) findViewById(R.id.sendTextField);
Handler = new Handler() {
#Override public void handleMessage(Message msg) {
String text = (String)msg.obj;
uartRX.append(text);
}
};
Thread t = new Thread(new Runnable() {
public void run()
{
Message msg = new Message();
msg.obj = "Start Serial Listen\n";
Handler.sendMessage(msg);
rxUART();
}
public void rxUART()
{
manager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbSerialDriver rxDriver = UsbSerialProber.acquire(manager);
if (rxDriver != null) {
try {
rxDriver.open();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
int byteSize = 0;
String data = "";
while(true)
{
byte[] arr = null;
try {
rxDriver.setBaudRate(115200);
rxDriver.read(arr, byteSize);
data = new String(arr);
Message msg = new Message();
msg.obj = data;
Handler.sendMessage(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
t.start();
}
public void sendUART(String data)
{
manager = (UsbManager) getSystemService(Context.USB_SERVICE);
// Find the first available driver.
UsbSerialDriver driver = UsbSerialProber.acquire(manager);
if (driver != null) {
try {
driver.open();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
driver.setBaudRate(115200);
byte buffer[] = new byte[16];
int numBytesRead = driver.read(buffer, 1000);
Log.d(TAG, "Read " + numBytesRead + " bytes.");
byte temp[] = data.getBytes();
driver.write(temp, 16);
} catch (IOException e) {
// Deal with error.
} finally {
try {
driver.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public void onClickSendBtn(View v)
{
String data = "";
data = sendTextField.getText().toString();
sendUART(data);
sendTextField.setText(" ");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Can anyone help me figure out why the app crashes on the code created in the thread?
Note: the code also crashes when not in a thread. Code was originally a function called by sendUART() to check for a response. no while(true) either.
Logcat:
11-02 09:49:22.988: E/AndroidRuntime(22652): FATAL EXCEPTION: Thread-964
11-02 09:49:22.988: E/AndroidRuntime(22652): java.lang.NullPointerException
11-02 09:49:22.988: E/AndroidRuntime(22652): at com.example.sensortest.MainActivity$2.rxUART(MainActivity.java:143)
11-02 09:49:22.988: E/AndroidRuntime(22652): at com.example.sensortest.MainActivity$2.run(MainActivity.java:119)
11-02 09:49:22.988: E/AndroidRuntime(22652): at java.lang.Thread.run(Thread.java:856)
The line numbers referenced are:
Thread t = new Thread(new Runnable() {
public void run()
{
Message msg = new Message();
msg.obj = "Start Serial Listen\n";
Handler.sendMessage(msg);
rxUART();
}
public void rxUART()
{
manager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbSerialDriver rxDriver = UsbSerialProber.acquire(manager);
if (rxDriver != null) {
try {
rxDriver.open();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
int byteSize = 0;
String data = "";
while(true)
{
byte[] arr = null;
try {
rxDriver.setBaudRate(115200);
rxDriver.read(arr, byteSize);
data = new String(arr);
Message msg = new Message();
msg.obj = data;
Handler.sendMessage(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
t.start();
You don't handle the case rxDriver == null in rxUart() correctly.
The if() statement skips the open() call only, but the while() loop gets executed with rxDriver being NULL resulting in NPE. You have the same problem in `sendUART(), btw.
Related
As i am working on OBD Reader Demo .Through my app i am trying to connect obd reader device and my app is installed in Nexus 7.OBD Reader device is connecting to other apps which is available on google play but if i am connecting with my app it is getting error java.io.IOException: bt socket closed, read return: -1 after connection establish .Any suggestions...
=========================================================
**MainActivity:-**
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.virgosys.demo.commands.SpeedObdCommand;
import com.virgosys.demo.commands.engine.EngineRPMObdCommand;
import com.virgosys.demo.commands.fuel.FindFuelTypeObdCommand;
public class MainActivity extends Bluetooth {
#SuppressWarnings("unused")
private Button On, Off, Visible, list;
private BluetoothAdapter BA;
private Set<BluetoothDevice> pairedDevices;
#SuppressWarnings("unused")
private ListView lv;
private BluetoothDevice device;
// private UUID uuid;
// private BluetoothSocketWrapper bluetoothSocket;
private BluetoothSocket socket;
private String deviceAddress;
String RPM, Speed, FuelType;
private TextView uuidTextView, deviceTextView, showRpm, showSpeed,
showFuelType, tv_connection_e, tv_connection_f;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showRpm = ((TextView) findViewById(R.id.show_rpm));
showSpeed = ((TextView) findViewById(R.id.txt_speed));
showFuelType = ((TextView) findViewById(R.id.txt_fueltype));
uuidTextView = ((TextView) findViewById(R.id.txt_uuid));
deviceTextView = ((TextView) findViewById(R.id.txt_device));
// tv_connection_e = ((TextView) findViewById(R.id.txt_device));
// tv_connection_f = ((TextView) findViewById(R.id.show_error));
On = (Button) findViewById(R.id.button1);
Off = (Button) findViewById(R.id.button2);
Visible = (Button) findViewById(R.id.button3);
list = (Button) findViewById(R.id.button4);
lv = (ListView) findViewById(R.id.listView1);
BA = BluetoothAdapter.getDefaultAdapter();
try {
Process process = Runtime.getRuntime().exec("logcat -d");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder log = new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
}
TextView tv_connection_e = (TextView) findViewById(R.id.show_error);
tv_connection_e.setText(log.toString());
} catch (IOException e) {
}
}
public void on(View view) {
if (!BA.isEnabled()) {
Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(turnOn, 0);
Toast.makeText(getApplicationContext(), "Turned on",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "Already on",
Toast.LENGTH_LONG).show();
}
}
#SuppressWarnings("unchecked")
public void list(View view) {
ArrayList deviceStrs = new ArrayList();
final ArrayList devices = new ArrayList();
BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
pairedDevices = btAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
deviceStrs.add(device.getName() + "\n" + device.getAddress());
devices.add(device.getAddress());
}
}
// show list
final AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
ArrayAdapter adapter = new ArrayAdapter(this,
android.R.layout.select_dialog_singlechoice,
deviceStrs.toArray(new String[deviceStrs.size()]));
alertDialog.setSingleChoiceItems(adapter, -1,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
int position = ((AlertDialog) dialog).getListView()
.getCheckedItemPosition();
deviceAddress = (String) devices.get(position);
System.out.println("Device Address-->" + deviceAddress);
/*
* Intent i = new Intent(MainActivity.this,
* SecondActivity.class); i.putExtra("uuid",
* "00001101-0000-1000-8000-00805F9B34FB");
* i.putExtra("deviceAddress", deviceAddress);
* i.putExtra("RPM", RPM); i.putExtra("Speed", Speed);
* startActivity(i);
*/
try {
dothings();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// save deviceAddress
}
});
alertDialog.setTitle("Choose Bluetooth device");
alertDialog.show();
}
#SuppressLint("NewApi")
protected void dothings() throws InterruptedException {
System.out.println("Inside Do things");
System.out.println("Device address in Do things -->" + deviceAddress);
device = BA.getRemoteDevice(deviceAddress);
// UUID SERIAL_UUID = device.getUuids()[0].getUuid();
// uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
System.out.println("Device Name-->" + device.getName());
System.out.println("Device Address-->" + device.getAddress());
System.out.println("Device Bond State-->" + device.getBondState());
System.out.println("Device Type-->" + device.getType());
System.out.println("Device UUIDS-->" + device.getUuids());
ConnectThread t = new ConnectThread(device);
t.start();
showRpm.setText(RPM);
showSpeed.setText(Speed);
showFuelType.setText(FuelType);
uuidTextView.setText("00001101-0000-1000-8000-00805F9B34FB");
deviceTextView.setText(deviceAddress);
}
public void off(View view) {
BA.disable();
Toast.makeText(getApplicationContext(), "Turned off", Toast.LENGTH_LONG)
.show();
}
public void visible(View view) {
Intent getVisible = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(getVisible, 0);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final UUID WELL_KNOWN_UUID = UUID
.fromString("00001101-0000-1000-8000-00805f9b34fb");
private Object e;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,because
// mmSocket is final
BluetoothSocket tmp = null;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(WELL_KNOWN_UUID);
// This is the trick
Method m = device.getClass().getMethod("createRfcommSocket",
new Class[] { int.class });
tmp = (BluetoothSocket) m.invoke(device, 1);
} catch (Exception e) {
e.printStackTrace();
}
mmSocket = tmp;
}
public void run() {
System.out.println("Trying to connect...");
// Cancel discovery because it will slow down the connection
BA.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
System.out.println("Connection established");
// tv_connection_e.setText(e.print.stacktrace);
ConnectedThread tc = new ConnectedThread(mmSocket);
tc.start();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
System.out.println("Fail to connect!");
try {
mmSocket.close();
} catch (IOException closeException) {
System.out.println("Fail to close connection");
}
return;
}
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
}
System.out.println("Inside the thread");
mmInStream = tmpIn;
mmOutStream = tmpOut;
try {
EngineRPMObdCommand engineRpmCommand = new EngineRPMObdCommand();
SpeedObdCommand speedCommand = new SpeedObdCommand();
FindFuelTypeObdCommand fueltypeCommand = new FindFuelTypeObdCommand();
System.out.println("Inside the try block");
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Inside while");
// TODO handle commands result
Log.d("Poonam",
"RPM: " + engineRpmCommand.getFormattedResult());
Log.d("Poonam",
"Speed: " + speedCommand.getFormattedResult());
Log.d("Poonam",
"FuelType: " + fueltypeCommand.getFormattedResult());
RPM = engineRpmCommand.getFormattedResult();
Speed = speedCommand.getFormattedResult();
FuelType = fueltypeCommand.getFormattedResult();
try {
engineRpmCommand.run(mmInStream, mmOutStream);
speedCommand.run(mmInStream, mmOutStream);
fueltypeCommand.run(mmInStream, mmOutStream);
System.out.println("Commands Processed");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("outside try catch");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("inside catch before while");
}
// Get the input and output streams, using temp objects because
// member streams are final
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) {
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
}
}
**Bluetooth.java**
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
public class Bluetooth extends Activity{
private BluetoothSocketWrapper bluetoothSocket;
private BluetoothDevice device;
private boolean secure;
private BluetoothAdapter adapter;
private List<UUID> uuidCandidates;
private int candidate;
/**
* #param device the device
* #param secure if connection should be done via a secure socket
* #param adapter the Android BT adapter
* #param uuidCandidates a list of UUIDs. if null or empty, the Serial PP id is used
* #return
*/
public void BluetoothConnector(BluetoothDevice device, boolean secure, BluetoothAdapter adapter,
List<UUID> uuidCandidates) {
this.device = device;
this.secure = secure;
this.adapter = adapter;
this.uuidCandidates = uuidCandidates;
if (this.uuidCandidates == null || this.uuidCandidates.isEmpty()) {
this.uuidCandidates = new ArrayList<UUID>();
this.uuidCandidates.add(UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"));
}
}
public BluetoothSocketWrapper connect() throws IOException {
boolean success = false;
while (selectSocket()) {
adapter.cancelDiscovery();
try {
bluetoothSocket.connect();
success = true;
break;
} catch (IOException e) {
//try the fallback
try {
bluetoothSocket = new FallbackBluetoothSocket(bluetoothSocket.getUnderlyingSocket());
Thread.sleep(500);
bluetoothSocket.connect();
success = true;
break;
} catch (FallbackException e1) {
Log.w("BT", "Could not initialize FallbackBluetoothSocket classes.", e);
} catch (InterruptedException e1) {
Log.w("BT", e1.getMessage(), e1);
} catch (IOException e1) {
Log.w("BT", "Fallback failed. Cancelling.", e1);
}
}
}
if (!success) {
throw new IOException("Could not connect to device: "+ device.getAddress());
}
return bluetoothSocket;
}
private boolean selectSocket() throws IOException {
if (candidate >= uuidCandidates.size()) {
return false;
}
BluetoothSocket tmp = null;
UUID uuid = uuidCandidates.get(candidate++);
Log.i("BT", "Attempting to connect to Protocol: "+ uuid);
if (secure) {
Method m = null;
try {
m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
tmp = (BluetoothSocket) m.invoke(device, 1);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(uuid);
}
bluetoothSocket = new NativeBluetoothSocket(tmp);
return true;
}
public static interface BluetoothSocketWrapper {
InputStream getInputStream() throws IOException;
OutputStream getOutputStream() throws IOException;
String getRemoteDeviceName();
void connect() throws IOException;
String getRemoteDeviceAddress();
void close() throws IOException;
BluetoothSocket getUnderlyingSocket();
}
public static class NativeBluetoothSocket implements BluetoothSocketWrapper {
private BluetoothSocket socket;
public NativeBluetoothSocket(BluetoothSocket tmp) {
this.socket = tmp;
}
#Override
public InputStream getInputStream() throws IOException {
return socket.getInputStream();
}
#Override
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
}
#Override
public String getRemoteDeviceName() {
return socket.getRemoteDevice().getName();
}
#Override
public void connect() throws IOException {
socket.connect();
}
#Override
public String getRemoteDeviceAddress() {
return socket.getRemoteDevice().getAddress();
}
#Override
public void close() throws IOException {
socket.close();
}
#Override
public BluetoothSocket getUnderlyingSocket() {
return socket;
}
}
public class FallbackBluetoothSocket extends NativeBluetoothSocket {
private BluetoothSocket fallbackSocket;
public FallbackBluetoothSocket(BluetoothSocket tmp) throws FallbackException {
super(tmp);
try
{
Class<?> clazz = tmp.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE};
Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[] {Integer.valueOf(1)};
fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params);
}
catch (Exception e)
{
throw new FallbackException(e);
}
}
#Override
public InputStream getInputStream() throws IOException {
return fallbackSocket.getInputStream();
}
#Override
public OutputStream getOutputStream() throws IOException {
return fallbackSocket.getOutputStream();
}
#Override
public void connect() throws IOException {
fallbackSocket.connect();
}
#Override
public void close() throws IOException {
fallbackSocket.close();
}
}
public static class FallbackException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public FallbackException(Exception e) {
super(e);
}
}
}
(MainActivity.java:367)
try {
engineRpmCommand.run(mmInStream, mmOutStream);
speedCommand.run(mmInStream, mmOutStream);
fueltypeCommand.run(mmInStream, mmOutStream);
System.out.println("Commands Processed");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
367--> e.printStackTrace();
}
System.out.println("outside try catch");
}
(ObdCommand.java:164)
protected void readRawData(InputStream in) throws IOException {
byte b = 0;
StringBuilder res = new StringBuilder();
// read until '>' arrives
164--> while ((char) (b = (byte) in.read()) != '>')
res.append((char) b);
Have you checked if your string builder / buffer contains anything at the time the exception is thrown?
I've had this trouble with Bluetooth on a Nexus 7 2012 and the only thing I can suggest is that you Thread.sleep() while waiting for data and use .available() from the stream to make sure you don't read more than what is available.
You could sleep loop while .available() is zero and not equal to the amount as the last loop, and then assume you have all the data when it stabilizes. Alternatively you can simply catch the exception and assume you have received all the data at that point.
I think its a bug in read() method. From #Keilaron's answer.. I tried this and this works:
while (inputStream.available() == 0);
val available = inputStream.available()
val bytes = ByteArray(available)
inputStream.read(bytes, 0, available)
val text = String(bytes)
I have an Android app, which should receive and read NMEA-sentences
e.g. $GPGLL,3751.65,S,14507.36,E*77
from a remote TCP-Server using Telnet protocol. I am using the org.apache.commons.net.telnet.TelnetClient library.
What works:
Connecting to Server
Reading some sentences without any error
Problem:
There are more than half of the sentences missing. I guess that it is a timing problem, perhaps this has also to do with the connection which gets restarted in every iteration.
Here is my MainActivity.java:
package com.example.clienttel;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import org.apache.commons.net.telnet.TelnetClient;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Go to ClientThread, where NMEA-sentences will be received
int i;
for (i = 0; i < 10000; i++) // 10000 for testing
new Thread(new ClientThread()).start();
}
class ClientThread implements Runnable {
//#Override
public void run() {
TelnetClient telnet = new TelnetClient();
// Variables
String ADDRESS = "194.66.82.11";
int PORT = 51000;
String NMEA = null;
final String TAG = "TestApp";
// Connect To Server
try {
telnet.connect(ADDRESS, PORT);
} catch (IOException e) {
e.printStackTrace();
}
// Process NMEA-sentences
InputStream inStream = telnet.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(inStream));
try {
NMEA = r.readLine();
} catch (IOException e) {
e.printStackTrace();
}
// Ignore "...busy" sentences
if (NMEA != null) {
if(!(NMEA.equals("*** Serial port is busy ***"))) {
Log.i(TAG, NMEA);
}
}
// Disconnect From Server
try {
telnet.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Any help would be appreciated!
EDIT:
My code now looks like this:
package com.example.clienttel;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import org.apache.commons.net.telnet.TelnetClient;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class MainActivity extends ActionBarActivity {
// Variables
public String ADDRESS = "194.66.82.11";
public int PORT = 50100;
public String NMEA = null;
public final String TAG = "TestApp";
public boolean first = true;
// Handler in mainthread
Handler handler = new Handler() {
public void handleMessage(Message msg) {
String dataString = "";
Bundle bundle = msg.getData();
Log.d("handleMessage", bundle.toString());
if (bundle.containsKey("outgoingString")) {
dataString = bundle.getString("outgoingString");
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ClientThread ct;
ct = new ClientThread();
ct.mhandler=handler;
int i;
for (i = 0; i < 10000; i++) { // 10000 for testing
// Go to ClientThread, where NMEA-sentences will be received
//new Thread(new ClientThread()).start();
ct.start();
}
}
class ClientThread implements Runnable {
public Handler mhandler = null;
#Override
public void run() {
TelnetClient telnet = new TelnetClient();
if (first) {
// Connect To Server in 1st Iteration
try {
telnet.connect(ADDRESS, PORT);
} catch (IOException e) {
e.printStackTrace();
}
first = false;
}
// Process NMEA-sentences
InputStream inStream = telnet.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(inStream));
try {
NMEA = r.readLine();
} catch (IOException e) {
e.printStackTrace();
}
// Handler in ClientThread to send back
Bundle b = new Bundle();
b.putString("outgoingString", NMEA);
Message m = mhandler.obtainMessage();
m.setData(b);
mhandler.sendMessage(m);
}
}
}
but I am not sure about the placement of the handlers
As #EJP said, opening an closing the connection for each line will kill the app...
A better approach is have the thread handle the communication(s) and wait for the next line, passing the data back to the main thread as a bundle message.
There are plenty of examples out there, but essentially you create a handler in your main thread:
Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
String dataString = "";
Bundle bundle = msg.getData();
Log.d("handleMessage", bundle.toString());
if (bundle.containsKey("outgoingString"))
{
dataString = bundle.getString("outgoingString");
}
// you can handle other message types here....
}
and pass it (the handler) to your ClientThread (here, as mhandler) where you can send the messages back:
Bundle b = new Bundle();
b.putString("outgoingString", outgoingText);
Message m = mhandler.obtainMessage();
m.setData(b);
mhandler.sendMessage(m);
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
Im' writing a sample chat program that sends message between 2 android phones, so I wrote the following and let a phone connect to itself(10.0.2.2 or localhost) to test it the code works or not.
But looks like in the thread of receivemsg(), the socket is never connected. So did I use the wrong ip address to refer to myself? or does my code have something wrong? thank you for your help!
package com.example.chatroomprogram;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
public class ClientActivity extends Activity {
private Handler handler = new Handler();
public ListView msgView;
public ArrayAdapter<String> msgList;
// public ArrayAdapter<String> msgList=new ArrayAdapter<String>(this,
// android.R.layout.simple_list_item_1);;
public String ipaddress;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
Intent intent = getIntent();
ipaddress=intent.getStringExtra("ipaddress");
Log.i("123","ip is "+ipaddress);
msgView = (ListView) findViewById(R.id.listView);
msgList = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1);
msgView.setAdapter(msgList);
// msgView.smoothScrollToPosition(msgList.getCount() - 1);
Button btnSend = (Button) findViewById(R.id.btn_Send);
receiveMsg();
btnSend.setOnClickListener(new View.OnClickListener() {
#SuppressLint("NewApi")
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
final EditText txtEdit = (EditText) findViewById(R.id.txt_inputText);
//msgList.add(txtEdit.getText().toString());
sendMessageToServer(txtEdit.getText().toString());
msgView.smoothScrollToPosition(msgList.getCount() - 1);
}
});
// receiveMsg();
//----------------------------
//server msg receieve
//-----------------------
//End Receive msg from server//
}
public void sendMessageToServer(String str) {
final String str1=str;
new Thread(new Runnable() {
#Override
public void run() {
//String host = "opuntia.cs.utep.edu";
//String host="10.0.";
String host2 = "10.0.2.2";
PrintWriter out = null;
Socket socket = null;
try {
socket = new Socket("10.0.2.2", 8008);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out = new PrintWriter(socket.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.i("123","not null");
// out.println("hello");
out.println(str1);
Log.i("123", "hello");
out.flush();
}
}).start();
}
public void receiveMsg()
{
new Thread(new Runnable()
{
#Override
public void run() {
// TODO Auto-generated method stub
//final String host="opuntia.cs.utep.edu";
final String host="10.0.2.2";
//final String host="127.0.0.1";
Socket socket = null ;
BufferedReader in = null;
try {
//socket = new Socket(host,8008);
ServerSocket ss = new ServerSocket(8008);
socket = ss.accept();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while(true)
{
String msg = null;
try {
msg = in.readLine();
Log.i("123","MSGGG: "+ msg);
//msgList.add(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(msg == null)
{
break;
}
else
{
displayMsg(msg);
}
}
}
}).start();
}
public void displayMsg(String msg)
{
final String mssg=msg;
handler.post(new Runnable() {
#SuppressLint("NewApi")
#Override
public void run() {
// TODO Auto-generated method stub
msgList.add(mssg);
msgView.setAdapter(msgList);
msgView.smoothScrollToPosition(msgList.getCount() - 1);
Log.i("123","hi");
}
});
}
}
update: Problem solved, conclusion: if you use AVD, just use 10.0.2.2; if you use an actual phone to debug, you can use localhost
my bad... i used 10.0.2.2 and it works...
I am trying to build a small photo app with a burst mode for camera. The main idea is to shoot a picture every 0,3sec and to store the pictures in an Array until the last picture is taken. The number of pictures to shoot should specified.
I can only shoot a picture every 2sec. as shortest interval. Then, when the pictures should be written to storage, the applications chrashes.
Does someone know how to implement this? Here is my code:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
public class CamaeaView extends Activity implements SurfaceHolder.Callback, OnClickListener {
static final int FOTO_MODE = 1;
private static final String TAG = "Test";
Camera mCamera;
boolean mPreviewRunning = false;
private Context mContext = this;
ArrayList<Object> listImage = null;
public static ArrayList<Object> List1[];
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Log.e(TAG, "onCreate");
#SuppressWarnings("unused")
Bundle extras = getIntent().getExtras();
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);
mSurfaceView.setOnClickListener(this);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData, Camera c) {
Log.d("Start: ","Imagelist");
Intent mIntent = new Intent();
listImage.add(StoreByteImage(imageData));
SaveImage(listImage);
mCamera.startPreview();
setResult(FOTO_MODE, mIntent);
finish();
}
};
protected void onResume() {
Log.d(TAG, "onResume");
super.onResume();
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
protected void onStop() {
Log.e(TAG, "onStop");
super.onStop();
}
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated");
mCamera = Camera.open();
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.d(TAG, "surfaceChanged");
// XXX stopPreview() will crash if preview is not running
if (mPreviewRunning) {
mCamera.stopPreview();
}
Camera.Parameters p = mCamera.getParameters();
p.setPreviewSize(w, h);
p.setPictureSize(1024, 768);
p.getSupportedPictureFormats();
p.setPictureFormat(PixelFormat.JPEG);
mCamera.setParameters(p);
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mCamera.startPreview();
mPreviewRunning = true;
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e(TAG, "surfaceDestroyed");
mCamera.stopPreview();
mPreviewRunning = false;
mCamera.release();
}
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
public void onClick(View arg0) {
int i = 0;
while (i < 4) {
mCamera.takePicture(null, mPictureCallback, mPictureCallback);
i = i + 1;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static Object StoreByteImage(byte[] imageData) {
Object obj = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(imageData);
ObjectInputStream objImageData = new ObjectInputStream(bis);
obj = objImageData.readObject();
} catch (IOException ex) {
// TODO: Handle the exception
} catch (ClassNotFoundException ex) {
// TODO: Handle the exception
}
return obj;
}
public static Object createImagesArray(byte[] imageData) {
Object obj = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(imageData);
ObjectInputStream objImageData = new ObjectInputStream(bis);
obj = objImageData.readObject();
} catch (IOException ex) {
// TODO: Handle the exception
} catch (ClassNotFoundException ex) {
// TODO: Handle the exception
}
return obj;
}
public static boolean SaveImage(List<Object> listImage) {
FileOutputStream outStream = null;
Log.d("ListSize: ", Integer.toString(listImage.size()));
Iterator<Object> itList = listImage.iterator();
byte[] imageBytes = null;
while (itList.hasNext()) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(listImage);
oos.flush();
oos.close();
bos.close();
imageBytes = bos.toByteArray();
} catch (IOException ex) {
// TODO: Handle the exception
}
try {
// Write to SD Card
outStream = new FileOutputStream(String.format(
"/sdcard/DCIM/%d.jpg", System.currentTimeMillis())); // <9>
outStream.write(imageBytes);
outStream.close();
} catch (FileNotFoundException e) { // <10>
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
Log.d(TAG, "onPictureTaken - jpeg");
return true;
}
}
Error from the comments:
ERROR/MemoryHeapBase(1382): error opening /dev/pmem_camera: No such file or directory
ERROR/QualcommCameraHardware(1382): failed to construct master heap for pmem pool /dev/pmem_camera
ERROR/QualcommCameraHardware(1382): initRaw X failed with pmem_camera, trying with pmem_adsp
AFAIK, you cannot take another picture until the first one is complete. Eliminate your for loop and Thread.sleep(). Take the next picture in mPictureCallback.
The main idea is to shoot a picture every 0,3sec and to store the pictures in an Array until the last picture is taken.
The "0,3sec" objective is faster than most devices can process an image, and you may not have enough heap space for your array of images. I suspect that you will have to write each image out to disk as it comes in via an AsyncTask, so you can free up the heap space while also not tying up the main application thread.
You can try capturing subsequent preview frames in preallocated byte arrays.
See the following methods:
http://developer.android.com/reference/android/hardware/Camera.html#addCallbackBuffer(byte[])
http://developer.android.com/reference/android/hardware/Camera.html#setPreviewCallbackWithBuffer(android.hardware.Camera.PreviewCallback)
...or http://developer.android.com/reference/android/hardware/Camera.html#setOneShotPreviewCallback(android.hardware.Camera.PreviewCallback) for better control over timing.
I am trying to write a twitter application on Android target 2.2 (using some sample code that I found on the net and using Marko Gargenta's O'Reilly text). I am stuck with the problem as in the log below. The source code is given first followed by the log. Any idea what's going wrong here ? Also does anyone have or can point to a sample jtwitter code working on Android.
Thanks,
Ravi
protected String doInBackground(String... statuses) {
try {
//Autho information
/*OAuthSignpostClient oauthclient = new OAuthSignpostClient(cons_key,
cons_secret, access_token, access_secret);*/
OAuthSignpostClient oauthclient = new OAuthSignpostClient(access_token, access_secret,"oob");
//***POSTING TO TWITTER CURRENTLY DOES NOT WORK WITH THIS INTERFACE
twitter = new Twitter(mytwitterusername, oauthclient);
//twitter.setAPIRootUrl("http://learningandroid.status.net/api");
//***POSTING TO TWITTER CURRENTLY DOES NOT WORK WITH THIS INTERFACE
Log.i(Logtag, "Status currently is " + statuses[0]);
Twitter.Status status = twitter.updateStatus(statuses[0]);
//return status.text;
return statuses[0];
} catch (TwitterException e) {
Log.e(Logtag, e.toString());
e.printStackTrace();
return "Failed to post to Twitter";
}
}
Log file:
E/dalvikvm( 719): Could not find method javax.swing.JOptionPane.showInputDialog, referenced from method winterwell.jtwi
tter.OAuthSignpostClient.askUser
W/dalvikvm( 719): VFY: unable to resolve static method 443: Ljavax/swing/JOptionPane;.showInputDialog (Ljava/lang/Objec
t;)Ljava/lang/String;
W/dalvikvm( 719): VFY: rejecting opcode 0x71 at 0x0000
W/dalvikvm( 719): VFY: rejected Lwinterwell/jtwitter/OAuthSignpostClient;.askUser (Ljava/lang/String;)Ljava/lang/Strin
g;
W/dalvikvm( 719): Verifier rejected class Lwinterwell/jtwitter/OAuthSignpostClient;
W/dalvikvm( 719): threadid=17: thread exiting with uncaught exception (group=0x4000fe70)
E/AndroidRuntime( 719): Uncaught handler: thread AsyncTask #1 exiting due to uncaught exception
E/AndroidRuntime( 719): java.lang.RuntimeException: An error occured while executing doInBackground()
E/AndroidRuntime( 719): at android.os.AsyncTask$3.done(AsyncTask.java:200)
E/AndroidRuntime( 719): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:234)
E/AndroidRuntime( 719): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:258)
E/AndroidRuntime( 719): at java.util.concurrent.FutureTask.run(FutureTask.java:122)
E/AndroidRuntime( 719): at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:648)
E/AndroidRuntime( 719): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:673)
E/AndroidRuntime( 719): at java.lang.Thread.run(Thread.java:1058)
E/AndroidRuntime( 719): Caused by: java.lang.VerifyError: winterwell.jtwitter.OAuthSignpostClient
E/AndroidRuntime( 719): at com.ravi.tweeto.StatusActivity$PostToTwitter.doInBackground(StatusActivity.java:81)
E/AndroidRuntime( 719): at com.ravi.tweeto.StatusActivity$PostToTwitter.doInBackground(StatusActivity.java:1)
E/AndroidRuntime( 719): at android.os.AsyncTask$2.call(AsyncTask.java:185)
E/AndroidRuntime( 719): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:256)
E/AndroidRuntime( 719): ... 4 more
I/Process ( 585): Sending signal. PID: 719 SIG: 3
I/dalvikvm( 719): threadid=7: reacting to signal 3
I/dalvikvm( 719): Wrote stack trace to '/data/anr/traces.txt'
----
Basically the JTwitter library has calls to Java swing classes that are not in the Android SDK as it does not use swing. I had to get the source for JTwitter and remove the swing code for my application to work. Hope this helps.
Might be worth looking at using the Twitter4J library as an alternative. I've had no issues using it within an Android application.
I found most of the code I use somewhere on GitHub (can't find the exact link right now)
A few searches on snippets of the code send me here, but I don't think that was the exact site I got it from.
But this is what I have in my semi-working code.
OAUTH.java
import junit.framework.Assert;
import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.OAuthProvider;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthProvider;
import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthExpectationFailedException;
import oauth.signpost.exception.OAuthMessageSignerException;
import oauth.signpost.exception.OAuthNotAuthorizedException;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
public class OAUTH extends Activity {
private static final String TAG = "OAUTH";
public static final String USER_TOKEN = "user_token";
public static final String USER_SECRET = "user_secret";
public static final String REQUEST_TOKEN = "request_token";
public static final String REQUEST_SECRET = "request_secret";
public static final String TWITTER_REQUEST_TOKEN_URL = "http://twitter.com/oauth/request_token";
public static final String TWITTER_ACCESS_TOKEN_URL = "http://twitter.com/oauth/access_token";
public static final String TWITTER_AUTHORIZE_URL = "http://twitter.com/oauth/authorize";
private static final Uri CALLBACK_URI = Uri.parse("gpsagenda://twitt");
public static final String PREFS = "MyPrefsFile";
private OAuthConsumer mConsumer = null;
private OAuthProvider mProvider = null;
SharedPreferences mSettings;
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// We don't need to worry about any saved states: we can reconstruct the state
mConsumer = new CommonsHttpOAuthConsumer(
"myKey",
"mySecret");
mProvider = new CommonsHttpOAuthProvider (
TWITTER_REQUEST_TOKEN_URL,
TWITTER_ACCESS_TOKEN_URL,
TWITTER_AUTHORIZE_URL);
// It turns out this was the missing thing to making standard Activity launch mode work
mProvider.setOAuth10a(true);
mSettings = this.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
Intent i = this.getIntent();
if (i.getData() == null) {
try {
// This is really important. If you were able to register your real callback Uri with Twitter, and not some fake Uri
// like I registered when I wrote this example, you need to send null as the callback Uri in this function call. Then
// Twitter will correctly process your callback redirection
String authUrl = mProvider.retrieveRequestToken(mConsumer, CALLBACK_URI.toString());
saveRequestInformation(mSettings, mConsumer.getToken(), mConsumer.getTokenSecret());
this.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthNotAuthorizedException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
}
}
#Override
protected void onResume() {
super.onResume();
Uri uri = getIntent().getData();
if (uri != null && CALLBACK_URI.getScheme().equals(uri.getScheme())) {
String token = mSettings.getString(OAUTH.REQUEST_TOKEN, null);
String secret = mSettings.getString(OAUTH.REQUEST_SECRET, null);
Intent i = new Intent(this, DetailsContainer.class); // Currently, how we get back to main activity.
try {
if(!(token == null || secret == null)) {
mConsumer.setTokenWithSecret(token, secret);
}
String otoken = uri.getQueryParameter(OAuth.OAUTH_TOKEN);
String verifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);
// We send out and save the request token, but the secret is not the same as the verifier
// Apparently, the verifier is decoded to get the secret, which is then compared - crafty
// This is a sanity check which should never fail - hence the assertion
Assert.assertEquals(otoken, mConsumer.getToken());
// This is the moment of truth - we could throw here
mProvider.retrieveAccessToken(mConsumer, verifier);
// Now we can retrieve the goodies
token = mConsumer.getToken();
secret = mConsumer.getTokenSecret();
OAUTH.saveAuthInformation(mSettings, token, secret);
// Clear the request stuff, now that we have the real thing
OAUTH.saveRequestInformation(mSettings, null, null);
i.putExtra(USER_TOKEN, token);
i.putExtra(USER_SECRET, secret);
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthNotAuthorizedException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
} finally {
startActivity(i); // we either authenticated and have the extras or not, but we're going back
finish();
}
}
}
public static void saveRequestInformation(SharedPreferences settings, String token, String secret) {
// null means to clear the old values
SharedPreferences.Editor editor = settings.edit();
if(token == null) {
editor.remove(OAUTH.REQUEST_TOKEN);
Log.d(TAG, "Clearing Request Token");
}
else {
editor.putString(OAUTH.REQUEST_TOKEN, token);
Log.d(TAG, "Saving Request Token: " + token);
}
if (secret == null) {
editor.remove(OAUTH.REQUEST_SECRET);
Log.d(TAG, "Clearing Request Secret");
}
else {
editor.putString(OAUTH.REQUEST_SECRET, secret);
Log.d(TAG, "Saving Request Secret: " + secret);
}
editor.commit();
}
public static void saveAuthInformation(SharedPreferences settings, String token, String secret) {
// null means to clear the old values
SharedPreferences.Editor editor = settings.edit();
if(token == null) {
editor.remove(OAUTH.USER_TOKEN);
Log.d(TAG, "Clearing OAuth Token");
}
else {
editor.putString(OAUTH.USER_TOKEN, token);
Log.d(TAG, "Saving OAuth Token: " + token);
}
if (secret == null) {
editor.remove(OAUTH.USER_SECRET);
Log.d(TAG, "Clearing OAuth Secret");
}
else {
editor.putString(OAUTH.USER_SECRET, secret);
Log.d(TAG, "Saving OAuth Secret: " + secret);
}
editor.commit();
}
}
DetailsTwitter.java (my "implementation")
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthExpectationFailedException;
import oauth.signpost.exception.OAuthMessageSignerException;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.gpsagenda.OAUTH;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class DetailsTwitter extends Activity {
public SharedPreferences mSettings;
private LinkedList<UserStatus> mHomeStatus = new LinkedList<UserStatus>();
public String mToken;
public String mSecret;
private OAuthConsumer mConsumer = null;
private HttpClient mClient;
private EditText mEditor;
private TextView mLast;
private CheckBox mCB;
private Button mButton;
private TextView mUser;
private int ID;
public static final String VERIFY_URL_STRING = "http://twitter.com/account/verify_credentials.json";
public static final String PUBLIC_TIMELINE_URL_STRING = "http://twitter.com/statuses/public_timeline.json";
public static final String USER_TIMELINE_URL_STRING = "http://twitter.com/statuses/user_timeline.json";
public static final String HOME_TIMELINE_URL_STRING = "http://api.twitter.com/1/statuses/home_timeline.json";
public static final String FRIENDS_TIMELINE_URL_STRING = "http://api.twitter.com/1/statuses/friends_timeline.json";
public static final String STATUSES_URL_STRING = "http://twitter.com/statuses/update.json";
ProgressDialog postDialog = null;
public static final String TWITTER_REQUEST_TOKEN_URL = "http://twitter.com/oauth/request_token";
public static final String TWITTER_ACCESS_TOKEN_URL = "http://twitter.com/oauth/access_token";
public static final String TWITTER_AUTHORIZE_URL = "http://twitter.com/oauth/authorize";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detailstwittertab);
HttpParams parameters = new BasicHttpParams();
HttpProtocolParams.setVersion(parameters, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(parameters, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(parameters, false);
HttpConnectionParams.setTcpNoDelay(parameters, true);
HttpConnectionParams.setSocketBufferSize(parameters, 8192);
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
ClientConnectionManager tsccm = new ThreadSafeClientConnManager(parameters, schReg);
mClient = new DefaultHttpClient(tsccm, parameters);
mCB = (CheckBox) this.findViewById(R.id.enable);
mCB.setChecked(false);
mEditor = (EditText) this.findViewById(R.id.editor);
mButton = (Button) this.findViewById(R.id.post);
mUser = (TextView) this.findViewById(R.id.user);
mLast = (TextView) this.findViewById(R.id.last);
mSettings = getSharedPreferences(OAUTH.PREFS, Context.MODE_PRIVATE);
mConsumer = new CommonsHttpOAuthConsumer(
"myKey",
"mySecret");
}
public void PostTweet(View v) {
String postString = mEditor.getText().toString();
if (postString.length() == 0) {
Toast.makeText(this, getText(R.string.tweet_empty), Toast.LENGTH_SHORT).show();
} else {
BitlyAndroid bitly = new BitlyAndroid("iarwain01", "R_1bffd0176aa731a27e5b2d23cf043199");
String shortUrl = "";
// Try to get the corresponding ID of the POI
try
{
ID = getIntent().getExtras().getInt("id");
} catch (NullPointerException e)
{
e.printStackTrace();
}
try {
shortUrl = bitly.getShortUrl("http://gpsagenda.ikdoeict.be/projecten2/index.php?module=places&id=" + ID);
} catch (Exception e) {
Log.e("Debug", "Link shortening failed!");
e.printStackTrace();
}
new PostTask().execute(postString + " " + shortUrl);
}
}
protected void onFinish() {
mClient.getConnectionManager().shutdown();
}
public void ConnectWithTwitter(View v)
{
if(mCB.isChecked()) {
Intent i = new Intent(this, OAUTH.class);
startActivity(i);
} else {
OAUTH.saveAuthInformation(mSettings, null, null);
mButton.setEnabled(false);
mEditor.setEnabled(false);
mCB.setChecked(false);
mUser.setText("");
}
mCB.setChecked(false); // the oauth callback will set it to the proper state
}
#Override
public void onResume()
{
super.onResume();
// We look for saved user keys
if(mSettings.contains(OAUTH.USER_TOKEN) && mSettings.contains(OAUTH.USER_SECRET)) {
mToken = mSettings.getString(OAUTH.USER_TOKEN, null);
mSecret = mSettings.getString(OAUTH.USER_SECRET, null);
if(!(mToken == null || mSecret == null)) {
mConsumer.setTokenWithSecret(mToken, mSecret);
}
}
new GetCredentialsTask().execute();
}
// These parameters are needed to talk to the messaging service
public HttpParams getParams() {
// Tweak further as needed for your app
HttpParams params = new BasicHttpParams();
// set this to false, or else you'll get an Expectation Failed: error
HttpProtocolParams.setUseExpectContinue(params, false);
return params;
}
//----------------------------
// This task posts a message to your message queue on the service.
private class PostTask extends AsyncTask<String, Void, JSONObject> {
ProgressDialog postDialog;
#Override
protected void onPreExecute() {
postDialog = ProgressDialog.show(DetailsTwitter.this,
getText(R.string.tweet_progress_title),
getText(R.string.tweet_progress_text),
true, // indeterminate duration
false); // not cancel-able
}
#Override
protected JSONObject doInBackground(String... params) {
JSONObject jso = null;
try {
HttpPost post = new HttpPost("http://twitter.com/statuses/update.json");
LinkedList<BasicNameValuePair> out = new LinkedList<BasicNameValuePair>();
out.add(new BasicNameValuePair("status", params[0]));
post.setEntity(new UrlEncodedFormEntity(out, HTTP.UTF_8));
post.setParams(getParams());
// sign the request to authenticate
mConsumer.sign(post);
String response = mClient.execute(post, new BasicResponseHandler());
jso = new JSONObject(response);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} finally {
}
return jso;
}
// This is in the UI thread, so we can mess with the UI
protected void onPostExecute(JSONObject jso) {
postDialog.dismiss();
if(jso != null) { // authorization succeeded, the json object contains the user information
mEditor.setText("");
mLast.setText(getCurrentTweet(jso));
} else {
mLast.setText(getText(R.string.tweet_error));
}
}
}
// Get stuff from the two types of Twitter JSONObject we deal with: credentials and status
private String getCurrentTweet(JSONObject status) {
return status.optString("text", getString(R.string.bad_value));
}
//----------------------------
// This task is run on every onResume(), to make sure the current credentials are valid.
// This is probably overkill for a non-educational program
private class GetCredentialsTask extends AsyncTask<Void, Void, JSONObject> {
ProgressDialog authDialog;
#Override
protected void onPreExecute() {
authDialog = ProgressDialog.show(DetailsTwitter.this,
getText(R.string.auth_progress_title),
getText(R.string.auth_progress_text),
true, // indeterminate duration
false); // not cancel-able
}
#Override
protected JSONObject doInBackground(Void... arg0) {
JSONObject jso = null;
HttpGet get = new HttpGet(VERIFY_URL_STRING);
try {
mConsumer.sign(get);
String response = mClient.execute(get, new BasicResponseHandler());
jso = new JSONObject(response);
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return jso;
}
// This is in the UI thread, so we can mess with the UI
protected void onPostExecute(JSONObject jso) {
authDialog.dismiss();
mCB.setChecked(jso != null);
mButton.setEnabled(jso != null);
mEditor.setEnabled(jso != null);
mUser.setText(jso != null ? getUserName(jso) : getString(R.string.userhint));
mLast.setText(jso != null ? getLastTweet(jso) : getString(R.string.userhint));
if(jso != null) {
TimelineSelector ss = new TimelineSelector(HOME_TIMELINE_URL_STRING);
new GetTimelineTask().execute(ss);
}
}
}
private String getLastTweet(JSONObject credentials) {
try {
JSONObject status = credentials.getJSONObject("status");
return getCurrentTweet(status);
} catch (JSONException e) {
e.printStackTrace();
return getString(R.string.tweet_error);
}
}
private String getUserName(JSONObject credentials) {
return credentials.optString("name", getString(R.string.bad_value));
}
private class TimelineSelector extends Object {
public String url; // the url to perform the query from
// not all these apply to every url - you are responsible
public Long since_id; // ids newer than this will be fetched
public Long max_id; // ids older than this will be fetched
public Integer count; // # of tweets to fetch Max is 200
public Integer page; // # of page to fetch (with limits)
public TimelineSelector(String u) {
url = u;
max_id = null;
since_id = null;
count = null;
page = null;
}
#SuppressWarnings("unused")
public TimelineSelector(String u, Long since, Long max, Integer cnt, Integer pg) {
url = u;
max_id = max;
since_id = since;
count = cnt;
page = pg;
}
}
private class UserStatus {
JSONObject mStatus;
#SuppressWarnings("unused")
JSONObject mUser;
public UserStatus(JSONObject status) throws JSONException {
mStatus = status;
mUser = status.getJSONObject("user");
}
#SuppressWarnings("unused")
public long getId() {
return mStatus.optLong("id", -1);
}
/*public String getUserName() {
return mUser.optString("name", getString(R.string.bad_value));
}
public String getText() {
return getCurrentTweet(mStatus);
}
public String getCreatedAt() {
#SuppressWarnings("unused")
Time ret1 = new Time();
return mStatus.optString("created_at", getString(R.string.bad_value));
}*/
}
private class GetTimelineTask extends AsyncTask<TimelineSelector, Void, JSONArray> {
#Override
protected JSONArray doInBackground(TimelineSelector... params) {
JSONArray array = null;
try {
for(int i = 0; i < params.length; ++i) {
Uri sUri = Uri.parse(params[i].url);
Uri.Builder builder = sUri.buildUpon();
if(params[i].since_id != null) {
builder.appendQueryParameter("since_id", String.valueOf(params[i].since_id));
} else if (params[i].max_id != null) { // these are mutually exclusive
builder.appendQueryParameter("max_id", String.valueOf(params[i].max_id));
}
if(params[i].count != null) {
builder.appendQueryParameter("count", String.valueOf((params[i].count > 200) ? 200 : params[i].count));
}
if(params[i].page != null) {
builder.appendQueryParameter("page", String.valueOf(params[i].page));
}
HttpGet get = new HttpGet(builder.build().toString());
mConsumer.sign(get);
String response = mClient.execute(get, new BasicResponseHandler());
array = new JSONArray(response);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
return array;
}
// This is in the UI thread, so we can mess with the UI
protected void onPostExecute(JSONArray array) {
if(array != null) {
try {
for(int i = 0; i < array.length(); ++i) {
JSONObject status = array.getJSONObject(i);
UserStatus s = new UserStatus(status);
mHomeStatus.add(s);
}
//mAA.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
} else {
}
}
}
}
My AndroidManifest.xml
<activity android:name="DetailsTwitter" />
<activity android:name="OAUTH" >
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:scheme="gpsagenda" android:host="twitt" />
</intent-filter>
</activity>
This should be enough to get you going, I hope.
If something is wrong in here, pleas do comment.
Regards,
iarwain