I am writing a chat client in Android using the XMPP protocol. I have used the asmack.jar as provided by
http://asmack.freakempire.de/. The implementation works in plain Java (using smack.jar) which I have tested. But in Android, I can only send messages to the other client (he uses pidgin) and cannot receive messages from him. The app successfully connects to the server, logs in and appears online but simply doesn't receive any message.
My processMessage() never gets called nor does chatCreated() when a message is send to my client.
My Activity class:
package com.example.basicchat;
import org.jivesoftware.smack.AndroidConnectionConfiguration;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.ChatManagerListener;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.SmackAndroid;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SmackAndroid.init(this);
MainActivity2 xmppClient= new MainActivity2("jabber.org", 5222);
try {
xmppClient.login();
} catch (XMPPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public class MainActivity2 implements MessageListener, ChatManagerListener, ConnectionListener {
private String server;
private int port;
public MainActivity2( String server, int port )
{
super();
this.server = server;
this.port = port;
}
private XMPPConnection connection = null;
public void login() throws XMPPException
{
String username = "my_user";
String password = "xxxxxxxx";
login(username, password);
}
private void login(String userName, String password) throws XMPPException
{
AndroidConnectionConfiguration config = new AndroidConnectionConfiguration(server,
port);
connection = new XMPPConnection(config);
connection.connect();
connection.addConnectionListener(this);
connection.login(userName, password);
ChatManager chatManager = connection.getChatManager();
chatManager.addChatListener(this);
Toast.makeText(MainActivity.this,"listener set", Toast.LENGTH_SHORT).show();
// sendMessage("helloooo","command_server#jabber.org"); /* this mssg is sent */
}
private void sendMessage(String message, String to) throws XMPPException
{
Chat chat = connection.getChatManager().createChat(to, this);
chat.sendMessage(message);
}
public void disconnect()
{
connection.disconnect();
}
/** never gets called **/
#Override
public void processMessage(Chat chat, Message message)
{
/*********** Handle Request and construct response ******************/
Toast.makeText(MainActivity.this,"mssg: "+message.getBody(), Toast.LENGTH_SHORT).show();
switch (message.getType())
{
case chat:
String jsonData = (null==message.getBody())?"":message.getBody();
System.out.println(jsonData);
break;
case error:
break;
case groupchat:
break;
case headline:
break;
case normal:
break;
}
}
#Override
public void chatCreated(Chat arg0, boolean arg1) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this,"Chat Created!", Toast.LENGTH_SHORT).show();
if (!arg1)
arg0.addMessageListener(this);
}
#Override
public void connectionClosed() {
// TODO Auto-generated method stub
}
#Override
public void connectionClosedOnError(Exception arg0) {
// TODO Auto-generated method stub
}
#Override
public void reconnectingIn(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void reconnectionFailed(Exception arg0) {
// TODO Auto-generated method stub
}
#Override
public void reconnectionSuccessful() {
// TODO Auto-generated method stub
}
}
}
Manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.basicchat"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme"
>
<activity
android:name="com.example.basicchat.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
You must implements MessageListener class for MainActivity to receive chat messages
Related
I have a method "send()" that send values to the server and then get response 0 or 1 from the server. then i want to active a method that check if its 0 or 1 and then i want to active a method that on MainActivity that called from the service.
this is the service code
public class SendThreadCommunication extends Thread {
private final static String TAG = "SendThreadCommunication";
private final int READ_TIMEOUT = 100000;
private final int CONNECTION_TINEOUT = 100000;
private Looper myLooper;
private int mResponseCode;
private String mData = "";
private final ServerRequest req;
// private RegisterUser user;
private static String ans;
public SendThreadCommunication(ServerRequest req) {
this.req = req;
}
public String readWebData(InputStream stream) {
String line = "";
StringBuffer buffer = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
try {
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
}
return buffer.toString();
}
#Override
public void run() {
try {
send();
// evaluateDataAndRespondToFragment(mData);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void send() throws ClientProtocolException, IOException {
OutputStream mOutputStream = null;
BufferedWriter mWriter = null;
List<NameValuePair> mParameters = req.getParameters();
URL url = null;
HttpURLConnection connection = null;
try {
Looper.prepare();
url = new URL(req.returnRequestUrl());
connection = (HttpURLConnection) url.openConnection();
connection.setReadTimeout(READ_TIMEOUT);
connection.setConnectTimeout(CONNECTION_TINEOUT);
connection.setRequestMethod(Params.HTTP_REQUEST_METHOD_POST);
connection.setDoOutput(true);
connection.setDoInput(true);
mOutputStream = connection.getOutputStream();
mWriter = new BufferedWriter(new OutputStreamWriter(mOutputStream, Params.UTF8));
String sparams = URLEncodedUtils.format(mParameters, Params.UTF8);
mWriter.write(sparams);
mWriter.flush();
mResponseCode = connection.getResponseCode();
if (mResponseCode > 203) {
mData = readWebData(connection.getErrorStream());
//this.req.getResponse().notGoodServerEroorr();
} else {
mData = readWebData(connection.getInputStream());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (connection != null) {
try {
if (mOutputStream != null)
mOutputStream.close();
if (mWriter != null)
mWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
connection.disconnect();
evaluateDataAndRespondToFragment(mData);
myLooper = Looper.myLooper();
Looper.loop();
myLooper.quit();
}
}
}
private void evaluateDataAndRespondToFragment(String mData) {
Listen lis = this.req.getResponse();
if (mData.equals("1"))
lis.good();
else
lis.notGood();
if (mData.equals("0"))
{
lis.userGcmNotRegistered();
}
}
}
this service code send to the server values and get response. the method "evaluateDataAndRespondToFragment" check if its 0 or 1 and then active the appropriate method. that method should trigger other method in the MainActivity.
i know that runOnUiThread handle this, but i dont know how to use it.
the method on the MainActivity change the UI.
this is the MainActivity code
public class MainActivity extends Activity implements SensorEventListener, Listen {
private BroadcastReceiver statusReceiver;
private IntentFilter mIntent;
Sensor accelerometer;
SensorManager sm;
TextView acceleration;
SendValues sv;
int counter3 = 0;
int counter5 = 0;
int pastTime = 0;
private static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void good() {
Toast.makeText(getApplication(), "successful transfer", Toast.LENGTH_LONG).show();
}
#Override
public void notGood() {
Toast.makeText(getApplication(), "UNsuccssful transfer", Toast.LENGTH_LONG).show();
}
#Override
public void userGcmNotRegistered() {
Toast.makeText(getApplication(), "There is some problem, please register again to the App", Toast.LENGTH_LONG).show();
}
}
Here it should active one of the methods "good","not good"....
i know that runOnUiThread handle it but i dont know how to use it and where.
if anyone could tell me what to do i will appreciate.
A service doesn't have a runOnUiThread method, but you can use intent instead of.
Simply,
Add a BroadcastReceiver to your activity,
Add receiver to your AndroidManifest.xml,
Send intent from your service.
MainActivity.java
public class MainActivity extends Activity implements SensorEventListener, Listen {
private BroadcastReceiver statusReceiver;
private IntentFilter mIntent;
Sensor accelerometer;
SensorManager sm;
TextView acceleration;
SendValues sv;
int counter3 = 0;
int counter5 = 0;
int pastTime = 0;
private static final String TAG = "MainActivity";
statusReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
switch(intent.getIntExtra("status", -1) {
case 1:
good();
break;
case 2:
notGood();
break;
default:
userGcmNotRegistered();
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerReceiver(statusReceiver, new IntentFilter("com.yourpackage.yourapp.GET_STATUS_INTENT");
}
#Override
public void good() {
Toast.makeText(getApplication(), "successful transfer", Toast.LENGTH_LONG).show();
}
#Override
public void notGood() {
Toast.makeText(getApplication(), "UNsuccssful transfer", Toast.LENGTH_LONG).show();
}
#Override
public void userGcmNotRegistered() {
Toast.makeText(getApplication(), "There is some problem, please register again to the App", Toast.LENGTH_LONG).show();
}
}
A simple AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yourpackage.yourapp"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.yourpackage.yourapp.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="MainActivity">
<intent-filter>
<action android:name="com.yourpackage.yourapp.GET_STATUS_INTENT">
</action>
</intent-filter>
</receiver>
</application>
</manifest>
evaluateDataAndRespondToFragment method
private void evaluateDataAndRespondToFragment(String mData) {
Intent intent = new Intent("com.yourpackage.yourapp.GET_STATUS_INTENT");
intent.putExtra(status, mData);
sendBroadcast(intent);
}
}
Additionally you need to register/unregister within your activity's onResume/onPause methods.
A bit off topic; but, Beremaran's answer is correct, you can't get the main thread from a service. However, runOnUiThread is a very important concept to know and use, to avoid blocking up your main thread. Blocking your main thread will cause the system to kill your app.
Let say you have some networking tasks to do, and you know that it can take some time to do that. Therefore you start a new Thread to do the slow work.
new Thread(new Runnable() {
#Override
public void run() {
messageFromSlowStuff = doSomeSlowStuff();
};
}).start();
Now you might want to populate the UI with the new data messageFromSlowStuff, but you can't because it is only aloud from the main thread.
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
myTextView.setText(messageFromSlowStuff)
}
});
If you are only updating a view as in the example above you can use View.post() an alternative to runOnUiThread.
myTextView.post(new Runnable() {
public void run() {
messageFromSlowStuff = doSomeSlowStuff();
myTextView.setText(messageFromSlowStuff);
}
});
Here's the docs regarding View.post(): "post reference"
I'm trying to implement a Server-Client communication via Push from Server to Client. Since the Client is an Android device, I'm using Google Cloud Messaging to fulfill pushing a message from server to android device. I followed this tutorial
Current status: The Client get's the Registry ID from GCM. So the client - GCM communication should be fine. The Server get's the following message while trying to push the message to gcm :
2015-01-20T23:31:24.289+0100|Information: Response Code : 200
2015-01-20T23:31:24.290+0100|Information: {"multicast_id":534481856434...,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1421793086402018%64d756d9f9fd7ecd"}]}
2015-01-20T23:31:24.296+0100|Information: com.sun.enterprise.web.connector.coyote.PECoyoteResponse$PECoyoteWriter#49...
It seems like the connection between client - gcm is working. But the gcm doesn't forward the message to my client.
My gcm project is also showing just 2 requests and over 2000 errors. I don't know that much about push notification to handle this issue, maybe somebody could help me.
Here's my code
Client MainActivity
// ... some other imports
import com.google.android.gms.gcm.GoogleCloudMessaging;
public class MainActivity extends ActionBarActivity implements OnCheckedChangeListener {
GoogleCloudMessaging gcm;
String regid;
String PROJECT_NUMBER = pn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getRegId();
}
public void getRegId() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
// TODO Auto-generated method stub
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(getApplicationContext());
}
regid = gcm.register(PROJECT_NUMBER);
msg = "Device registered, registration ID = " + regid;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
msg = "Error: " + e.getMessage();
}
Log.d("Systemablauf", "MainActivity getRegId() " + msg);
return msg;
}
}.execute(null, null, null);
}
}
Client MessageHandler
import com.google.android.gms.gcm.GoogleCloudMessaging;
public class GcmMessageHandler extends IntentService {
String msg;
private Handler handler;
public GcmMessageHandler(String name) {
super("GcmMessageHandler");
// TODO Auto-generated constructor stub
}
#Override
public void onCreate() {
super.onCreate();
handler = new Handler();
}
#Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
msg = extras.getString("title");
showToast();
Log.d("Systemablauf", "Received: (" + messageType + ") " + extras.getString("title"));
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
private void showToast() {
// TODO Auto-generated method stub
handler.post(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
});
}
}
Client BroadcastReceiver
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// Explicitly specify that GcmMessageHandler will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(), GcmMessageHandler.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
Log.d("Systemablauf", "onReceive()");
}
}
Client Manifest
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xml>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="thesis.com.example.clientsync"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<uses-permission
android:name="android.permission.INTERNET"/>
<uses-permission
android:name="android.permission.VIBRATE"/>
<uses-permission
android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission
android:name="android.permission.WAKE_LOCK"/>
<uses-permission
android:name="com.google.android.c2dm.permission.RECEIVE"/>
<permission
android:name="thesis.com.example.clientsync.permission.C2D_MESSAGE"
android:protectionLevel="signature"/>
<uses-permission
android:name="thesis.com.example.clientsync.permission.C2D_MESSAGE" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action
android:name="com.google.android.c2dm.intent.RECEIVE" />
<category
android:name="thesis.com.example.clientsync" />
</intent-filter>
</receiver>
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<service
android:name="service.MainService" />
</application>
</manifest>
Server Servlet
#WebServlet("/ServerServlet")
public class ServerServlet extends HttpServlet {
public ServerServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
sendNotification();
}
private void sendNotification() {
System.out.println("Sending POST to GCM");
String apiKey = "AIzaSyA0pOZf13cZzqQHrWBZfFE9XFMHA5ftiAo";
Content content = createContent();
POST2GCM.post(apiKey, content);
}
private static Content createContent() {
// TODO Auto-generated method stub
Content c = new Content();
c.addRegId("APA91bFrSX_mGLzLUf2Va6...");
c.createData("Test Title", "Test Message");
return c;
}
}
Server Post
public class POST2GCM {
public static void post(String apiKex, Content content) {
String apiKey = "AIzaSyA0pO...";
try {
URL url = new URL("https://android.googleapis.com/gcm/send");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Authorization", "key = " + apiKey);
connection.setDoOutput(true);
Gson gsonMapper = new GsonBuilder().create();
DataOutputStream writer = new DataOutputStream(connection.getOutputStream());
writer.writeBytes(gsonMapper.toJson(content));
writer.flush();
writer.close();
int responseCode = connection.getResponseCode();
System.out.println("\nSending 'POST' request to URL: " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null)
response.append(inputLine);
in.close();
System.out.println(response.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Server Content
#SuppressWarnings("serial")
public class Content implements Serializable {
private List<String> registration_ids;
private Map<String, String> data;
public void addRegId (String regId) {
if (registration_ids == null)
registration_ids = new LinkedList<String>();
registration_ids.add(regId);
}
public void createData (String title, String message) {
if (data == null)
data = new HashMap<String, String>();
data.put("title", title);
data.put("message", message);
}
}
Similar questions are already available. But in my case I checked both SHA1 and my scope, they are correct and the account is also available. But still it returns unknown GoogleAuthException. My code is :-
MainActivity.java
package com.simon.learn.accountgetter;
import java.io.IOException;
import java.util.ArrayList;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.UserRecoverableAuthException;
import com.google.android.gms.common.AccountPicker;
public class MainActivity extends Activity {
AccountManager am;
Account[] accounts;
ArrayList<String> accNames = new ArrayList<String>();
Button signin;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
am = AccountManager.get(getApplicationContext());
accounts = am.getAccountsByType("com.google");
// accounts=am.getAccounts();
signin = (Button) findViewById(R.id.signinBt);
signin.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = AccountPicker.newChooseAccountIntent(null,
null, new String[] { "com.google" }, false, null, null,
null, null);
startActivityForResult(intent, 13);
}
});
}
private void getToken(String accountName) {
new GetTokenTask(MainActivity.this, accountName,
"oauth2:https://www.googleapis.com/auth/userinfo.profile")
.execute();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
String token = null;
if (requestCode == 13) {
if (resultCode == RESULT_OK) {
String accountName = data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
Log.e("simon", accountName);
Toast.makeText(getApplicationContext(), accountName,
Toast.LENGTH_LONG).show();
getToken(accountName);
// Toast.makeText(getApplicationContext(),
// "The token is : "+token, Toast.LENGTH_LONG).show();
}
}
}
public class GetTokenTask extends AsyncTask<Void, Void, String> {
Activity activity;
String scope;
String email;
public GetTokenTask(Activity activity, String email, String scope) {
this.activity = activity;
this.scope = scope;
this.email = email;
}
#Override
protected String doInBackground(Void... params) {
String token = null;
try {
Log.e("simon","Scope : "+scope+ " email "+ email);
token = GoogleAuthUtil.getToken(activity, email, scope);
} catch (UserRecoverableAuthException e) {
// TODO Auto-generated catch block
Log.e("simon","UserRecoverableAuthException");
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e("simon","IOException");
e.printStackTrace();
} catch (GoogleAuthException e) {
// TODO Auto-generated catch block
Log.e("simon","GoogleAuthException : "+e.getMessage());
e.printStackTrace();
}
return token;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
Log.e("simon", "The Token is : " + result);
Toast.makeText(getApplicationContext(), "The Token is : " + result,
Toast.LENGTH_LONG).show();
super.onPostExecute(result);
}
}
}
It is showing unknown GoogleAuthException. See my manifest file also
Manifest.java
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.simon.learn.accountgetter"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Please help me. Thanks in advance
I am trying to start a service from a thread which I hava initialized with getApplicationContext() but context.startService returns null. I can't figure out why.
Thanks in advance.
Mainlogic.java
public class MainLogic extends Thread {
Context context;
public MainLogic(Context context) {
this.context = context;
}
ArrayList<Messenger> mClients = new ArrayList<Messenger>();
Messenger bluetoothService;
Messenger mMessanger = new Messenger(new MainHandler());
private class MainHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MessageType.NEW_HEARTH_RATE: {
//stuff
break;
}
case MessageType.REGISTER: {
mClients.add(msg.replyTo);break;
}
case MessageType.UNREGISTER: {
mClients.remove(msg.replyTo);break;
}
case MessageType.START_BLUETOOTH_SERVICE: {
startBluetoothService();
break;
}
default:
break;
}
}
}
private ServiceConnection bluetoothConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
Message msg = Message.obtain();
msg.what = MessageType.CONNECTION_ENDED;
msg.replyTo = mMessanger;
try {
bluetoothService.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
bluetoothService = new Messenger(service);
Message msg = Message.obtain();
msg.replyTo = mMessanger;
msg.what = MessageType.CONNECTION_ESTABLISHED;
try {
bluetoothService.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
public void startBluetoothService() {
//This is where i start the service
Intent intent = new Intent(context, BluetoothService.class);
ComponentName name= context.startService(intent);
//name equals null after startService
boolean bind=context.bindService(new Intent(context, BluetoothService.class),
//bind equals false after bindService
bluetoothConnection, Context.BIND_AUTO_CREATE);
}
#Override
public void run() {
while(true){
}
}
public Messenger getMessanger() {
return mMessanger;
}
}
BluetoothService.java:
public class BluetoothService extends Service {
private NumberGenerator nGenerator;
final Messenger mMessenger = new Messenger(new BluetoothServiceHandler());
ArrayList<Messenger> mClients = new ArrayList<Messenger>();
private final class BluetoothServiceHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
//random messaging
}
default:
break;
}
}
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("BluetoothService",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = Message.obtain();
msg.arg1 = startId;
msg.what = MessageType.START_NUMBERGENERATOR;
try {
mMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
return START_STICKY;
}
#Override
public void onDestroy() {
Message msg = Message.obtain();
msg.what = MessageType.BLUETOOTH_SERVICE_STOPED;
try {
mMessenger.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mMessenger.getBinder();
}
}
And this is how I start the thread:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainLogic mainLogic=new MainLogic(this.getApplicationContext());
mainLogic.setPriority(Thread.MAX_PRIORITY);
mainLogic.start();
mainMessenger=mainLogic.getMessanger();
Message message= Message.obtain();
message.what=MessageType.REGISTER;
message.replyTo=actMessenger;
try {
mainMessenger.send(message);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}}
Update 1: Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.bugra.bluetoothcomponent"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<service android:name="BluetoothService" />
<activity
android:name="com.bugra.bluetoothcomponent.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The problem is probably in the manifest declaration. You must have an exception when trying to start this service telling you that it is not found. You should put the fully qualified name of your service (with the package name), or at least a dot "." in front of the name if your Service is in the root package. Your manifest line should look like this:
<service android:name=".BluetoothService" />
Or:
<service android:name="com.bugra.bluetoothcomponent.BluetoothService" />
I am building a simple MQTT client for android, and I am getting the "Socket error for client identifier" error on the RMBS console. This only happens in the android implementation of the client ( I also created a Java desktop client and runs with no problems). For the Android client, I am suing the Paho Java client libraries. Here is my code:
This is the Android Client:
package com.example.mqttdroid;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.eclipse.paho.client.mqttv3.internal.MemoryPersistence;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;
public class MQTTClient extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mqttclient);
// new BackTask().execute(); not used because (seems to be the problem)
MqttConnectOptions conOpts = new MqttConnectOptions();
conOpts.setKeepAliveInterval(30);
conOpts.setWill(client.getTopic("Error"), "something bad happened".getBytes(), 1, true);
client.connect(conOpts);
client.subscribe("/House/Kitchen/Bulb");
client.setCallback( new MqttCallback() {
#Override
public void connectionLost(Throwable arg0) {
// TODO Auto-generated method stub
}
#Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
// TODO Auto-generated method stub
}
#Override
public void messageArrived(String arg0, MqttMessage arg1)
throws Exception {
// TODO Auto-generated method stub
Toast.makeText(Main.this, arg0.toString(), Toast.LENGTH_SHORT).show();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.mqttclient, menu);
return true;
}
/*public class BackTask extends AsyncTask<Void, Void, Void>{
private MqttClient client;
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
client = new MqttClient("tcp://"Ip of machine running RSMB":1883", "ANDROID1", new MemoryPersistence());
client.connect();
client.subscribe("House/Kitchen/Bulb");
} catch (MqttException e) {
// TODO Auto-generated catch block
Log.e("ERROR", "NOT CONNECTED");
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
try {
client.setCallback( new MqttCallback() {
#Override
public void messageArrived(MqttTopic arg0, MqttMessage arg1)
throws Exception {
// TODO Auto-generated method stub
Toast.makeText(MQTTClient.this, arg0.toString(), Toast.LENGTH_SHORT).show();
}
#Override
public void deliveryComplete(MqttDeliveryToken arg0) {
// TODO Auto-generated method stub
}
#Override
public void connectionLost(Throwable arg0) {
// TODO Auto-generated method stub
}
});
} catch (MqttException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}*/
This is the Desktop Java Client:
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.eclipse.paho.client.mqttv3.internal.MemoryPersistence;
public class MQTTBaseClass {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
MqttClientPersistence persistence;
try {
MqttClient client = new MqttClient("tcp://localhost:1883", "PC",new MemoryPersistence());
MqttConnectOptions conOpts = new MqttConnectOptions();
conOpts.setKeepAliveInterval(30);
conOpts.setWill(client.getTopic("Error"), "something bad happened".getBytes(), 1, true);
client.connect(conOpts);
MqttMessage msg = new MqttMessage("hello".getBytes());
msg.setQos(0);
msg.setRetained(true);
MqttTopic topic = client.getTopic("House/Kitchen/Bulb");
client.subscribe("House/Kitchen/Bulb");
try {
client.setCallback( new MqttCallback() {
#Override
public void messageArrived(MqttTopic arg0, MqttMessage arg1)
throws Exception {
// TODO Auto-generated method stub
System.out.println(arg1.toString());
}
#Override
public void deliveryComplete(MqttDeliveryToken arg0) {
// TODO Auto-generated method stub
}
#Override
public void connectionLost(Throwable arg0) {
// TODO Auto-generated method stub
}
});
} catch (MqttException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
topic.publish(msg);
} catch (MqttPersistenceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MqttException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Just a few notes:
I am connected on my android device via WiFi, and so is my desktop when I run the Java Dekstop client.
The Java Destop Client is running on the same machine as the RSMB
The Java Desktop Client creates and subscirbes to the topic "House/Kitchen/Bulb" and sends a message with the String "Hello"
The Android Client also subscribes to "House/Kitchen/Bulb" and attempts to display a Toast with the received message.
I have addeded the Internet permission on the android manifest
The android device seems to connect to the broker just fine, but as soon as I initialize the Java Desktop Service client (or the Paho client plug-in in Eclipse and publish a message) I get the error mentioned.
I ran the app using the emulator on the same machine the RSMB runs, and I get the same error.
What might be the problem?
UPDATE:
Originally, I got a "Network on Main Thread" Exception, so I moved the connect operation to an AsyncTask. Now it seems that the Android Client is still connected when I publish a message with the Java Client(Asynctask might have been creating issues), but the messageArrived() of the MqttCallback() doesn't seem to be called.
UPDATE 2:
I managed to make it work. Here is the code I am using now:
package com.example.mqttphone;
*import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;*
public class Main extends Activity {
protected static String msg;
public MqttClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
client = new MqttClient("tcp://10.1.201.27:1883", "ANDROID1", new MemoryPersistence());
MqttConnectOptions conOpts = new MqttConnectOptions();
conOpts.setKeepAliveInterval(30);
conOpts.setWill(client.getTopic("Error"), "something bad happened".getBytes(), 1, true);
client.setCallback( new MqttCallback() {
#Override
public void connectionLost(Throwable arg0) {
// TODO Auto-generated method stub
}
#Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
// TODO Auto-generated method stub
}
#Override
public void messageArrived(String arg0, MqttMessage arg1)
throws Exception {
// TODO Auto-generated method stub
Main.msg = arg1.toString();
Main.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(Main.this, msg, Toast.LENGTH_LONG).show();
}
});
Log.e("MESSAGE RECEIVED", arg1.toString());
}
});
client.connect(conOpts);
//MqttMessage msg = new MqttMessage("ANDROID MESSAGE".getBytes());
//client.getTopic("world").publish(msg);
if(client.isConnected()){
client.subscribe("/House/Kitchen/Bulb");
Toast.makeText(this, "CONNECTED", Toast.LENGTH_SHORT).show();
}
} catch (MqttException e) {
// TODO Auto-generated catch block
Log.e("ERROR", "NOT CONNECTED");
e.printStackTrace();
}
}
#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;
}
}
Hello I have use your code but I can not connect my paho client to my apollo server I have get below error.
I/global(677): Default buffer size used in BufferedOutputStream constructor. It would be better to be explicit if an 8k buffer is required.
E/ERROR(677): NOT CONNECTED
W/System.err(677): (32109) - java.io.EOFException
W/System.err(677): at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:127)
W/System.err(677): at java.lang.Thread.run(Thread.java:1096)
W/System.err(677): Caused by: java.io.EOFException
W/System.err(677): at java.io.DataInputStream.readFully(DataInputStream.java:266)
W/System.err(677): at org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream.readMqttWireMessage(MqttInputStream.java:63)
W/System.err(677): at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:94)
W/System.err(677): ... 1 more
Thanks
Girish
I got it working. Here is a link to the github repository where everyone can find a project that implements this code. It allows users to turn on a LED light remotely using their Android device via voice recognition.