Android: Wearable not receiving Message Api message - java

I am trying to send a message from an android phone to a wearable, but the onMessageReceived method in the WearableListenerService is never called. I have verified that the message from the phone sends successfully and to the right node, so the problem appears to be on the receiving end in the wearable app. Here is my code for the listener class in the wearable project:
public class MessageListener extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks {
#Override
public void onMessageReceived(MessageEvent messageEvent) {
if (messageEvent.getPath().equals("/message_path")) {
final String message = new String(messageEvent.getData());
// Broadcast message to wearable activity for display
Intent messageIntent = new Intent();
messageIntent.setAction(Intent.ACTION_SEND);
messageIntent.putExtra("message", message);
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
}
else {
super.onMessageReceived(messageEvent);
}
}
#Override
public void onPeerConnected(Node peer) {
Log.v("myTag", "Peer connected: " + peer.getDisplayName());
}
#Override
public void onConnected(Bundle bundle) {
Wearable.MessageApi.addListener(MainActivityWear.client, this);
}
#Override
public void onConnectionSuspended(int i) {}
}
By setting breakpoints, I found that neither the onMessageReceived method nor the onConnected method were called.
Here is the MainActivity for the wearable project:
public class MainActivityWear extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private TextView mTextView;
private MessageReceiver messageReceiver;
public static GoogleApiClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_wear);
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
mTextView = (TextView) stub.findViewById(R.id.text);
}
});
client = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
// Register the local broadcast receiver
IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
messageReceiver = new MessageReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);
}
// Connect to the data layer when the Activity starts
#Override
protected void onStart() {
super.onStart();
client.connect();
}
#Override
public void onStop() {
super.onStop();
unregisterReceiver(messageReceiver);
}
#Override
public void onConnected(#Nullable Bundle bundle) {}
#Override
public void onConnectionSuspended(int i) {}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {}
public class MessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
// Display message in UI
mTextView.setText(message);
}
}
}
The MessageReceiver is a nested class.
Everything compiles correctly, but the message is never received. Thank you in advance!

Check GoogleServicesAPI's version inside application and your devices. They must be the same.
Check whether your wear and handheld devices have the same version as your app. If not - use oldest one.
PS
do not use onPeerConnected and onConnectionSuspended. Those methods are deprecated and are not fired.

Related

Variable is showing value as null even when I had set already value of it

I have created background service to connect my socket server, it works background while app is off, when user open the app MainActivity join to my service class and it looks fine, my service can change fragment in main activity, but when it get disconnected and want to change fragment in main activity then app crash
check my MainActivity
public class MainActivity extends AppCompatActivity {
private clientService mclientService;
private Intent mServiceIntent;
private final FragmentManager fm = getFragmentManager();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mclientService = new clientService(this);
mServiceIntent = new Intent(this, mclientService.getClass());
if (!isMyServiceRunning(mclientService.getClass())) {
startService(mServiceIntent);
}
}
public Fragment changeFragment (Fragment cls) {
FragmentTransaction ft = this.fm.beginTransaction();
ft.replace(R.id.bodyFrame, cls);
ft.commit();
return cls;
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
Log.i ("isMyServiceRunning?", true+"");
return true;
}
}
Log.i ("isMyServiceRunning?", false+"");
return false;
}
}
and the clientService:
public class clientService extends Service {
private Socket mSocket;
{
try {
IO.Options opts = new IO.Options();
opts.query = "_d=jakistakiid";
mSocket = IO.socket("http://10.0.2.2:3000", opts);
} catch (URISyntaxException e) {}
}
public clientService(MainActivity main) {
super();
mainAttach(main);
}
public clientService() {
}
public MainActivity mMain;
public void startIt(){
Log.i("eroapp", "Service Started");
if(mSocket != null) {
mSocket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i("eroapp", "connected");
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i("eroapp", "dc:"+mMain);
onDC();
}
});
mSocket.connect();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startIt();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Intent broadcastIntent = new Intent(this, restartReceiver.class);
sendBroadcast(broadcastIntent);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
// CLIENT FUNCTIONS //
private void onDC(){
Log.i("eroapp", "DC:"+mMain);
}
private void mainAttach(MainActivity m) {
mMain = m;
Log.i("eroapp","Main created!");
if(!mSocket.connected()) {
mMain.changeFragment(new offlineFragment());
}else{
mMain.changeFragment(new singFragment());
}
}
}
looks fine, when i close app activity my service restarts and run in background, it says in logcat:
2019-11-17 02:41:22.686 17458-17458/com.example.secmsg I/eroapp: Service Started
2019-11-17 02:41:22.803 17458-17483/com.example.secmsg I/eroapp: connected
when i open app again, my service is already running, so its run only function mainAttach in clientService, and then service run changeFragment function in main activity, works great, but
when I get disconnected from server it says mMain is null ; < and logcat output:
2019-11-17 02:41:31.654 17458-17499/com.example.secmsg I/eroapp: dc:null
2019-11-17 02:41:31.654 17458-17499/com.example.secmsg I/eroapp: DCnull
The mclientService you created on the MainActivity is not the same as the clientService that was started by the Android system when you called startService(intent). All services created and started by the Android system by using the service class' empty constructor, therefore, clientService#mainAttach will never be called. Take a look at this answer for more information.
If you want to directly interact with the service on the MainActivity, you might want to bind the service to your activity. Check out the documentation about bound services here.
Another thing... It looks like you're planning to directly control the MainActivity from the service using the reference to the activity. Please never do that and use broadcasts instead. Good luck!

Calling a function in Android Started Service

I am developing an app to monitor changes in proximity sensor value. In app there should be two separate buttons to start a service and then to start monitoring proximity sensor.
This is my service class
public class MyService extends Service{
Sensor proxSensor;
SensorManager sm;
public static MyService instance;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
instance = this;
return Service.START_STICKY;
}
public void startScan(){
sm=(SensorManager)getSystemService(SENSOR_SERVICE);
proxSensor=sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);
SensorEventListener eventListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
Log.e("Sensor","Value "+sensorEvent.values[0]);
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
};
sm.registerListener(eventListener, proxSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
I am starting service from my main activity
public void viewNotification(View view){
startService(new Intent(this,MyService.class));
}
public void viewNotification2(View view){
MyService.instance.startScan();
}
The Log output is printed correctly while the app is running but when I close the activity and remove it from previous apps list the output is not given. But if I call startScan() within onStartCommand it goes on running even after I close the app.
Why doesn't it keep on giving the output?
Is there any other method instead of using static MyService to achieve this?
First of all - use service binding or aidl approaches for working with your Service. (see: https://developer.android.com/guide/components/bound-services.html)
For example:
Suppose, we have service named MyService.
In this class you need write next
private final IBinder mBinder = new LocalServiceBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalServiceBinder extends Binder {
public MyService getBinder() {
return MyService.this;
}
}
Next in your Activity:
private MyService mService;
boolean isBounded;
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected");
MyService.LocalServiceBinder binder = (MyService.LocalServiceBinder) service;
mService = binder.getBinder();
isBounded = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected");
isBounded = false;
}
};
And
#Override
protected void onStart() {
super.onStart();
bindService(new Intent(this, MyService.class), mServiceConnection, BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
if (isBounded) {
unbindService(mServiceConnection);
isBounded = false;
}
}
Now you can call your service methods like:
private void activityMethod(){
if (isBounded){
mService.someMethod();
}
}
Second, for working in foreground, call startForeground (int id, Notification notification) method.

How to show the Bluetooth Le Device connected/Disconnected status constantly

I am trying to develop an application where the user can know the status of his/her Bluetooth Le device once he/she launches the app and the connection status is updated in text view in Home Fragment.I have tried to implement it by sending Broadcast from Ble service and catching it in onResume of Home fragment and subsequently updating it in status text view. The status does gets updated but if I change the fragment and come back to the home fragment the text view to show the status gets blank although the Bluetooth Le device is connected.How can I resolve this problem so that the status shows connected all through out if the device is connected and disconnected if it is disconnected?
Any Kind of guidance will be highly appreciated.
here are the code segments I have used to implement the above
In Bleservice.java
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
In HomeFragment.java
public class HomeFragment extends Fragment
{
private BroadcastReceiver mReceiver;
#Override
protected void onResume() {
super.onResume();
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (Bleservice.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
updateConnectionState(R.string.connected);
} else if (Bleservice.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
}
}
};
getActivity().registerReceiver(mReceiver,makeGattUpdateIntentFilter());
}
private void updateConnectionState(final int resourceId) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
tv_connected_disconnected.setText(resourceId);
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
getActivity().unregisterReceiver(mReceiver);
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Bleservice.ACTION_GATT_CONNECTED);
intentFilter.addAction(Bleservice.ACTION_GATT_DISCONNECTED);
return intentFilter;
}
Connect to your BleService by bindService. Check out example with Activity and Service.
private BleService mBluetoothLeService;
private boolean isConnected;
#Override
protected void onStart() {
super.onStart();
Intent bindIntent = new Intent(this, BleService.class);
startService(bindIntent);
bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
registerServiceReceiver(); //register here your mGattCallback that get actions from BleService
}
#Override
protected void onStop() {
super.onStop();
unbindService(mServiceConnection);
mBluetoothLeService = null;
LocalBroadcastManager.getInstance(this).unregisterReceiver(mGattUpdateReceiver);
}
In method bindService you need to pass a ServiceConnection that manage Service Lifecycle.
// Code to manage Service lifecycle.
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BleService.LocalBinder) service).getService();
isConnected = (mBluetoothLeService.getConnectionState() != BleService.STATE_CONNECTED)
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
In Service you need to declare Binder.
private final IBinder mBinder = new LocalBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalBinder extends Binder {
public BleService getService() {
return BleService.this;
}
}
public int getConnectionState() {
return mConnectionState;
}
So now, after binding to BleService, you can get a connection state.

Communication between Activity and GCMListenerService Android

I am working on an android application with push notification feature using GCM. I have created a class called PushNotificationService which extends GCMListenerService. Inside the onMessageReceived(String from, Bundle data) I am able to get the message in the push notification.
Now, I want to access a method inside my MainActivity class whenever a particular message is received in the push.
Below is my code :-
PushNotificationService.java
public class PushNotificationService extends GcmListenerService {
#Override
public void onMessageReceived(String from, Bundle data) {
// TODO Auto-generated method stub
super.onMessageReceived(from, data);
String message = data.getString("message");
if(message.equalsIgnoreCase("Begin Task"))
{
//call method from MainActivity.class
}
}
}
MainActivty.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void beginTask()
{
Log.d("GCM","Message Received from Server");
finish();
}
}
I want the beginTask() method to execute whenever the message "Begin Task" is received.
I know one approach is via Service->Interface->Activity architecture but I am not able to use this as I never create an object of PushNotificationService.
Please help.
UPDATE :-
I am now using Otto Library and below is my code.
Added new MyBus.java
public class MyBus extends Bus {
private static Bus bus;
//isRegistered is used to track the current registration status
private static boolean isRegistered;
private Handler handler = new Handler(Looper.getMainLooper());
public MyBus() {
if (bus == null) {
//ANY will allow event bus to run even with services
//and broadcast receivers
bus = new Bus(ThreadEnforcer.ANY);
}
}
#Override
public void register(Object obj) {
//The bus is registered when an activity starts
bus.register(obj);
isRegistered = true;
}
#Override
public void unregister(Object obj) {
//The bus is unregistered when an activity goes to background
bus.unregister(obj);
isRegistered = false;
}
#Override
public void post(final Object event) {
if (Looper.myLooper() == Looper.getMainLooper()) {
//post the event in main thread or background thread
bus.post(event);
} else {
handler.post(new Runnable() {
#Override
public void run() {
bus.post(event);
}
});
}
}
public boolean isRegistered(){
return isRegistered;
}
}
PushNotificationService.java
public class PushNotificationService extends GcmListenerService {
#Override
public void onMessageReceived(String from, Bundle data) {
// TODO Auto-generated method stub
super.onMessageReceived(from, data);
MyBus myBus = new MyBus();
myBus.register(myBus);
String message = data.getString("message");
if(message.equalsIgnoreCase("Begin Task"))
{
myBus.post(message);
}
}
}
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Subscribe
public void beginTask()
{
Log.d("GCM","Message Received from Server");
}
}
The problem is still not solved. The beginTask() inside MainActivity.java is still not getting called.
Use eventBus libraries to facilitate this process...
I use Otto for this process
http://square.github.io/otto/
Here is an another eventBus library https://greenrobot.github.io/EventBus/
Steps:
1.Create an event from the service
2.Add a listener in the activity
3.If the activity is running the method will be executed
**EDIT 1 : **
I have abstracted the otto bus like this.
package com.mypackage.eventBus;
import android.os.Handler;
import android.os.Looper;
import com.squareup.otto.Bus;
import com.squareup.otto.ThreadEnforcer;
/**
* Created by gowtham on 10/6/15.
*/
public class MyBus extends Bus {
private static Bus bus;
//isRegistered is used to track the current registration status
private static boolean isRegistered;
private Handler handler = new Handler(Looper.getMainLooper());
public MyBus() {
if (bus == null) {
//ANY will allow event bus to run even with services
//and broadcast receivers
bus = new Bus(ThreadEnforcer.ANY);
}
}
#Override
public void register(Object obj) {
//The bus is registered when an activity starts
bus.register(obj);
isRegistered = true;
}
#Override
public void unregister(Object obj) {
//The bus is unregistered when an activity goes to background
bus.unregister(obj);
isRegistered = false;
}
#Override
public void post(final Object event) {
if (Looper.myLooper() == Looper.getMainLooper()) {
//post the event in main thread or background thread
bus.post(event);
} else {
handler.post(new Runnable() {
#Override
public void run() {
bus.post(event);
}
});
}
}
public boolean isRegistered(){
return isRegistered;
}
}
create an instance of the above object and try posting event
EDIT 2 for Jcarlo's comment
Follow these steps to find the state of the activity.
In your activity's onResume call MyBus.getInstance().register(this).
In your activity's onPause call MyBus.getInstance().unregister(this).
In your GCM IntentService before posting the message
if(MyBus.getInstance().isRegistered()){
//app is alive
//post data
}else{
//show notification
}
Hope this helps
You can use LocalBroadcastManager. Create a LocalBroadcastManager object mBroadcaster = LocalBroadcastManager.getInstance(this); on onCreate of your GCMListener and send broadcast with
#Override
public void onCreate() {
super.onCreate();
mBroadcaster = LocalBroadcastManager.getInstance(this);
}
#Override
public void onMessageReceived(String from, Bundle data) {
super.onMessageReceived(from, data);
String message = data.getString("message");
if(message.equalsIgnoreCase("Begin Task")) {
Intent i = new Intent();
i.setAction("yourPackageName");
i.putExtra("DATA", yourData);
mBroadcaster.send(i);
}
}
Then you can receive message in MainActivity using a BroadcastReceiver.
BroadCastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
beginTask();
}
};
Also you need to register and unregister the receiver in onStart and onStop of your activity
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter();
filter.addAction("yourPackageName);
LocalBroadcastManager.getInstance(this).registerReceiver((mBroadcastReceiver), filter);
}
#Override
protected void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
}

Notify Activity Class

I have 2 classes which are GcmMessageHandler and Control (its an activity class, shows some graphics). When i handle the gcm message, i want to refresh control class (but if its front)
public class GcmMessageHandler extends IntentService {
String mes;
private Handler handler;
public GcmMessageHandler() {
super("GcmMessageHandler");
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
handler = new Handler();
}
#Override
protected void onHandleIntent(Intent intent) {
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);
mes = extras.getString("title");
showToast();
Log.i("GCM", "Received : (" +messageType+") "+extras.getString("title"));
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
public void showToast(){
handler.post(new Runnable() {
public void run() {
if(mes.equals("Control")){
}else{
Toast.makeText(getApplicationContext(),mes , Toast.LENGTH_LONG).show();
}
}
});
}
}
In this part:
if(mes.equals("Control")){ }
if the control activity class is resume, i want to refresh it. How can i do this?
You can use a BroadcastReceiver in order to notify your activity about any changes. So register a BroadcastReceiver in your activity first:
public class MainActivity extends Activity {
public static String REFRESH_ACTIVITY = "com.domain.action.REFRESH_UI"
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do UI updates
}
};
#Override
public void onResume() {
super.onResume();
// do UI updates
IntentFilter filter = new IntentFilter();
filter.addAction(REFRESH_ACTIVITY);
this.registerReceiver(broadcastReceiver, filter);
}
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(broadcastReceiver);
}
...
}
Then send the broadcast to perform the UI update from any location:
if (mes.equals("Control")) {
Intent intent = new Intent();
intent.setAction(MainActivity.REFRESH_ACTIVITY);
sendBroadcast(intent);
}
Maybe you could use an observer design pattern.
Let the GcmMessageHandler hold the Control activity as an observer and then notify it when needed.
public class GcmMessageHandler extends IntentService {
String mes;
private Handler handler;
private Control mObserver
public GcmMessageHandler() {
super("GcmMessageHandler");
}
public void attachObserver(Control ctrl) {
mObserver = ctrl;
}
Then you just add a method to the Control class that can be called from the GcmMessageHandler class.
if(mes.equals("Control")){
mObserver.update(); // example
}else ...
It would be more slick if you first defined an observer interface:
public interface IObserver {
public abstract void update();
}
and had your Control class implement that. This way your GcmMessageHandler class could have a list of observers:
public class GcmMessageHandler extends IntentService {
String mes;
private Handler handler;
private List<IObserver> mObservers;
public GcmMessageHandler() {
super("GcmMessageHandler");
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
handler = new Handler();
mObservers = new ArrayList<IObserver>();
}
public void attachObserver(Control ctrl) {
mObservers.add(ctrl);
}
private void notify() {
for(IObserver observer : mObservers)
observer.update();
}
And of course if the Control class is the one holding the GcmMessageHandler object your just call the attach method from Control like this:
myGcmMessageHandler.attachObserver(this);

Categories