Search code examples
androidwear-osandroid-wear-data-api

Sending data from an Activity to WearableListenerService


When I read about communication between an Activity and Service, I found that we can use either

  • IBinder
  • Messenger
  • AIDL

I am interested in the first two. So when I tried implementing this to communicate between an Activity and WearableListenerService, I needed to override the onBind function.

But then, I am getting a compiler error saying it

cannot override final method "onBind"

I dont get such an error when I use a normal Service. So,

1. Does that mean we cannot use IBinder or Messenger approach to communicate with the WearableListenerService from an Activity?

2. If so, what is the next best way to pass message to WearableListenerService from an Activity (or call a public method of that service from an Activity)?


Solution

  • After some digging, I found the solution. Hope it helps somebody else.

    We can send message from an Activity to WearableListenerService using Wearable.MessageApi functions. When the Activity and WearableListenerService are on the same Node (device), we need to get the instance of the local node (current node from which the message is sent) for sending the message as below

    NodeApi.GetLocalNodeResult nodes = Wearable.NodeApi.getLocalNode(mGoogleApiClient).await();
    

    rather than

    NodeApi.GetConnectedNodesResult nodes  = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
    

    which is used to get the list of other devices (such as wear) connected to the phone.

    So, I was able to successfully send a message from my Activity to WearableListenerService as follows

    Activity Code

    public class PhoneActivity extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{
    
        private static final String TAG = "PhoneActivity";
    
        public static final String CONFIG_START = "config/start";
        public static final String CONFIG_STOP= "config/stop"
    
        Intent intent;
        TextView txtview;
    
        GoogleApiClient mGoogleApiClient;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_phone);
    
            if(null == mGoogleApiClient) {
                mGoogleApiClient = new GoogleApiClient.Builder(this)
                        .addApi(Wearable.API)
                        .addConnectionCallbacks(this)
                        .addOnConnectionFailedListener(this)
                        .build();
                Log.v(TAG, "GoogleApiClient created");
            }
    
            if(!mGoogleApiClient.isConnected()){
                mGoogleApiClient.connect();
                Log.v(TAG, "Connecting to GoogleApiClient..");
            }
    
            startService(new Intent(this, PhoneService.class));
        }
    
        @Override
        public void onConnectionSuspended(int cause) {
            Log.v(TAG,"onConnectionSuspended called");
        }
    
        @Override
        public void onConnectionFailed(ConnectionResult connectionResult) {
            Log.v(TAG,"onConnectionFailed called");
        }
    
        @Override
        public void onConnected(Bundle connectionHint) {
            Log.v(TAG,"onConnected called");
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Log.v(TAG, "onStart called");
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.phone, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
            if (id == R.id.action_start_) {
                new SendActivityPhoneMessage(CONFIG_START,"").start();
            }else if (id == R.id.action__stop) {
                new SendActivityPhoneMessage(CONFIG_STOP,"").start();
            }else if (id == R.id.action_settings) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    
        class SendActivityPhoneMessage extends Thread {
            String path;
            String message;
    
            // Constructor to send a message to the data layer
            SendActivityPhoneMessage(String p, String msg) {
                path = p;
                message = msg;
            }
    
            public void run() {
                NodeApi.GetLocalNodeResult nodes = Wearable.NodeApi.getLocalNode(mGoogleApiClient).await();
                Node node = nodes.getNode();
                Log.v(TAG, "Activity Node is : "+node.getId()+ " - " + node.getDisplayName());
                MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path, message.getBytes()).await();
                if (result.getStatus().isSuccess()) {
                    Log.v(TAG, "Activity Message: {" + message + "} sent to: " + node.getDisplayName());
                }
                else {
                    // Log an error
                    Log.v(TAG, "ERROR: failed to send Activity Message");
                }
            }
        }
    }
    

    Service Code

    public class PhoneService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{
    
        private static final String TAG = "PhoneService";
    
        public static final String CONFIG_START = "config/start";
        public static final String CONFIG_STOP = "config/stop";
    
        GoogleApiClient mGoogleApiClient;
    
        public PhoneService() {
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.v(TAG, "Created");
    
            if(null == mGoogleApiClient) {
                mGoogleApiClient = new GoogleApiClient.Builder(this)
                        .addApi(Wearable.API)
                        .addConnectionCallbacks(this)
                        .addOnConnectionFailedListener(this)
                        .build();
                Log.v(TAG, "GoogleApiClient created");
            }
    
            if(!mGoogleApiClient.isConnected()){
                mGoogleApiClient.connect();
                Log.v(TAG, "Connecting to GoogleApiClient..");
            }
        }
    
        @Override
        public void onDestroy() {
    
            Log.v(TAG, "Destroyed");
    
            if(null != mGoogleApiClient){
                if(mGoogleApiClient.isConnected()){
                    mGoogleApiClient.disconnect();
                    Log.v(TAG, "GoogleApiClient disconnected");
                }
            }
    
            super.onDestroy();
        }
    
        @Override
        public void onConnectionSuspended(int cause) {
            Log.v(TAG,"onConnectionSuspended called");
        }
    
        @Override
        public void onConnectionFailed(ConnectionResult connectionResult) {
            Log.v(TAG,"onConnectionFailed called");
        }
    
        @Override
        public void onConnected(Bundle connectionHint) {
            Log.v(TAG,"onConnected called");
    
        }
    
        @Override
        public void onDataChanged(DataEventBuffer dataEvents) {
            super.onDataChanged(dataEvents);
            Log.v(TAG, "Data Changed");
        }
    
        @Override
        public void onMessageReceived(MessageEvent messageEvent) {
            super.onMessageReceived(messageEvent);
            if(messageEvent.getPath().equals(CONFIG_START)){
                //do something here
            }else if(messageEvent.getPath().equals(CONFIG_STOP)){
                //do something here
            }
        }
    
        @Override
        public void onPeerConnected(Node peer) {
            super.onPeerConnected(peer);
            Log.v(TAG, "Peer Connected " + peer.getDisplayName());
        }
    
        @Override
        public void onPeerDisconnected(Node peer) {
            super.onPeerDisconnected(peer);
            Log.v(TAG, "Peer Disconnected " + peer.getDisplayName());
        }
    }