Search code examples
javaandroidwear-osandroid-wear-data-apigoogle-client

Sync Android Wear with Phone whenever you open the wear app


I am trying to implement a basic weather app for both android phone and wear. The application gets its data from an Web API then it displays it on the phone. Right now if the app is open on the Wear and then you open it on the Phone, it syncs the weather on both. And if you change the weather on the phone, it changes on the wear too. I want to make the wear app get the weather from the phone whenever you open the wear app, and I tried to implement this by making the wear "ping" the phone via a message and then the phone sends the info via a datamap. This works except the wear doesn't receive the datamap from the phone although the phone says it has sent the datamap.

Wear Main Activity:

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_data_map);
    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);
            sendMessage("Ping");
            Log.i("OnLayoutInflated","LAYOUT INFLATED");
        }
    });

    setAmbientEnabled();

    // Register the local broadcast receiver
    IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
    MessageReceiver messageReceiver = new MessageReceiver();
    LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);

}


@Override
protected void onPause() {

    super.onPause();
    if (wearCommsManager.isConnected()) {
        wearCommsManager.disconnectClient();
    }
}

@Override
protected void onResume() {
    super.onResume();

    if (wearCommsManager == null) {
        wearCommsManager = new WearCommsManager(this);
    }
    if (messageSender == null) {
        messageSender = new WearMessageSender(wearCommsManager);
    }
    verifyCommsConnection();
}
protected void sendMessage(final String message) {
    AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {

        @Override
        protected Void doInBackground(Void... params) {;
            messageSender.processRequest(message);
            return null;
        }
    };
    task.execute();
}


private void verifyCommsConnection() {
    new WearCommsManager(this).verifyCommsConnection(new WearCommsManager.CommsCallback() {
        @Override
        public void onSuccess() {

        }

        @Override
        public void onFailure() {
            Log.e("ERROR","CONNECTION FAILED");
        }

    });
}



public class MessageReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        Bundle data = intent.getBundleExtra("datamap");
        // Display received data in UI
        String display =
                 data.getString("city") + "\n" +
                 data.getString("temperature") + "\n" +
                 data.getString("wind_speed") + "\n" +
                 data.getString("cloud_percent")+"\n"+
                 data.getString("lastupdate");
        mTextView.setText(display);
    }
}

Wear Listener:

public class ListenerService extends WearableListenerService{

private static final String WEARABLE_DATA_PATH = "/wearable_data";


@Override
public void onCreate() {

    super.onCreate();
}

@Override
public void onDataChanged(DataEventBuffer dataEvents) {

    DataMap dataMap;
    for (DataEvent event : dataEvents) {
        Log.v("myTag", "DataMap received on watch: " + DataMapItem.fromDataItem(event.getDataItem()).getDataMap());
        // Check the data type
        if (event.getType() == DataEvent.TYPE_CHANGED) {
            // Check the data path
            String path = event.getDataItem().getUri().getPath();
            if (path.equals(WEARABLE_DATA_PATH)) {}
            dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();


            // Broadcast DataMap contents to wearable activity for display
            // The content has the golf hole number and distances to the front,
            // middle and back pin placements.

            Intent messageIntent = new Intent();
            messageIntent.setAction(Intent.ACTION_SEND);
            messageIntent.putExtra("datamap", dataMap.toBundle());
            LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);

        }
    }
}
}

Phone Main Activity:

public class DataMapActivity extends AppCompatActivity implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener{
private TextView cityName;
private TextView temp;
private ImageView iconView;
private TextView description;
private TextView humidity;
private TextView pressure;
private TextView wind;
private TextView sunrise;
private TextView sunset;
private TextView updated;

Weather weather = new Weather();

GoogleApiClient googleClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_data_map);

    cityName = (TextView) findViewById(R.id.cityText);
    iconView = (ImageView) findViewById(R.id.thumbnailIcon);
    temp = (TextView) findViewById(R.id.tempText);
    description = (TextView) findViewById(R.id.CloudText);
    humidity = (TextView) findViewById(R.id.HumidText);
    pressure = (TextView) findViewById(R.id.PressureText);
    wind = (TextView) findViewById(R.id.WindText);
    sunrise = (TextView) findViewById(R.id.RiseText);
    sunset = (TextView) findViewById(R.id.SetText);
    updated = (TextView) findViewById(R.id.UpdateText);
    CityPreference cityPreference=new CityPreference(DataMapActivity.this);
    System.out.println(cityPreference.getCity());
    renderWeatherData(cityPreference.getCity());

    IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
    MessageReceiver messageReceiver = new MessageReceiver();
    LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);

    // Build a new GoogleApiClient for the the Wearable API
    googleClient = new GoogleApiClient.Builder(this)
            .addApi(Wearable.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
}

public void renderWeatherData(String city) {
    WeatherTask weatherTask = new WeatherTask();
    weatherTask.execute(new String[]{city + "&units=metric"});
}

private class WeatherTask extends AsyncTask<String, Void, Weather> {
    @Override
    protected Weather doInBackground(String... params) {
        String data = ((new WeatherHttpClient()).getWeatherData(params[0]));
        System.out.println(data);
        weather = JSONParser.getWeather(data);
        return weather;
    }

    @Override
    protected void onPostExecute(Weather weather) {

        super.onPostExecute(weather);
        if(weather.currentCondition.getIcon() != null){
            new DownloadImageAsyncTask().execute(weather.currentCondition.getIcon());
        }
        cityName.setText(weather.place.getCity() + "," + weather.place.getCountry());
        temp.setText("" + (int)weather.currentCondition.getTemperature() + "°C");
        wind.setText("Wind Speed: " + weather.wind.getSpeed()+"m/s" + " Degree: " + weather.wind.getDegree());
        description.setText("Clouds: " + weather.clouds.getPrecipitation() + "%, " + weather.currentCondition.getDescription());
        pressure.setText("Pressure: " + weather.currentCondition.getPressure()+"hpa");
        humidity.setText("Humidity: " + weather.currentCondition.getHumidity()+"%");
        Date mydate = new Date(weather.place.getSunrise() * 1000);
        SimpleDateFormat dateformat = new SimpleDateFormat("HH:mm");
        dateformat.setTimeZone(TimeZone.getTimeZone("GMT+3"));
        String date = dateformat.format(mydate);
        sunrise.setText("Sunrise: " + date);
        mydate = new Date(weather.place.getSunset() * 1000);
        date = dateformat.format(mydate);
        sunset.setText("Sunset: " + date);
        mydate = new Date(weather.place.getLastupdate() * 1000);
        dateformat = new SimpleDateFormat("dd.MM.yyyy, HH:mm, z");
        dateformat.setTimeZone(TimeZone.getDefault());
        date = dateformat.format(mydate);
        updated.setText("Last Updated: " + date);
        sendWear();

        //This part synchronizes perfectly with wear 

    }

}

private void sendWear(){
    String WEARABLE_DATA_PATH = "/wear_data";

    // Create a DataMap object and send it to the data layer
    DataMap dataMap = new DataMap();
    dataMap.putString("lastupdate", updated.getText().toString());
    dataMap.putString("city", cityName.getText().toString());
    dataMap.putString("temperature", temp.getText().toString());
    dataMap.putString("wind_speed", wind.getText().toString());
    dataMap.putString("cloud_percent", description.getText().toString());
    //Requires a new thread to avoid blocking the UI
    new SendToDataLayerThread(WEARABLE_DATA_PATH, dataMap).start();
}

public class MessageReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

       String s= intent.getStringExtra("Pinger");
        if(s!=null) {
            new SendToWearAsyncTask().execute();

        }
    }
}

private class SendToWearAsyncTask extends AsyncTask<Void,Void,Void>{
    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        sendWear();
         //this part wear doesn't receive the datamap
    }

    @Override
    protected Void doInBackground(Void... params) {
        return null;
    }
}

Solution

  • Make sure that the applicationID were the same in the build.gradle for mobile and wear app. Also make sure that the buildTypes part and the signingConfigs part are the same in both apps. Source. You can also send Long.toString(System.currentTimeMillis()) to verify that as it changes every time.