androidandroid-intentbluetooth-lowenergywear-osgoogle-now

Android Wear DataItem Syncing / parallel use of Google now


I'm developing an app for android wear, which is collecting sensor data (e.g. acceleration, ..) and syncs it with corresponding app on mobile phone. Each time a sensor is triggered (onSensorChanged), the following code is executed:

Runnable runnable = new Runnable() {
        @Override
        public void run() {
            PutDataMapRequest dataMap = PutDataMapRequest.create(WearConstants.WTP_SENSOR_DATA_CHANGED + sensorType);

            dataMap.getDataMap().putInt(WearConstants.ACCURACY, accuracy);
            dataMap.getDataMap().putLong(WearConstants.TIMESTAMP_WEAR, timestamp);
            dataMap.getDataMap().putFloatArray(WearConstants.VALUES, values);

            Wearable.DataApi.putDataItem(mApiClient, dataMap.asPutDataRequest()).setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
                    @Override
                    public void onResult(DataApi.DataItemResult dataItemResult) {
                        Log.d(TAG, "Sending sensor data: " + dataItemResult.getStatus().isSuccess());
                    }
                });
        }
}; Thread thread = new Thread(runnable); thread.start();

This is working pretty well, the sensor data is transferred to mobile phone and displayed in the app. The second feature of the app is the possibility to take notes. There are two possibilites for taking notes: a) press a button while the app is opened and b) triggered by "Ok Google, take a note" while the app is closed. (see Google documentation)

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
startActivityForResult(intent, WearConstants.W_SPEECH);


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    switch (requestCode) {
        case WearConstants.W_SPEECH: {
            if (resultCode == RESULT_OK && data != null) {
                List<String> results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
                String spokenText = results.get(0);
                sendSpeech(spokenText);

            }
        }

    }
}

This is working well too, but only if the app is not listening for sensor changes. And this is the problem: each time I trigger a voice action while app (or background service) is listening for sensor changes, voice is not recognized and I am getting an error "Google not reachable". It seems to me like there is not enough capacity on the BluetoothLE connection. Therefore I tried to batch sensor data (in an ArrayList) and pause sending to mobile phone while listening to voice commands, but there was no difference. After five days trying to find a solution I am getting a little desperate now :-) I hope you have new ideas or tips what to try next.


Solution

  • After a couple of additional research it looks like I finally found a solution: When I tried to batch sensor data in the first run, I only paused sending. But when my limit was reached, I still sent each value separately. That was the big mistake. After chaning my data item to include an array of data maps, battery usage and performance looks pretty good. This is the code I am using now:

    
    
        DataMap dataMap = PutDataMapRequest.create(WearConstants.WTP_SENSOR_DATA_CHANGED + sensorType).getDataMap();
        dataMap.putInt(WearConstants.SENSOR, sensorType);
        dataMap.putInt(WearConstants.ACCURACY, accuracy);
        dataMap.putLong(WearConstants.TIMESTAMP_WEAR, timestamp);
        dataMap.putFloatArray(WearConstants.VALUES, values);
    
        dataMaps.add(dataMap);
    
        if(dataMaps.size() > maxMaps) {
            final ArrayList dataMapsCopy = (ArrayList) dataMaps.clone();
            dataMaps.clear();
    
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    PutDataMapRequest dataMap = PutDataMapRequest.create(WearConstants.WTP_SENSOR_DATA_CHANGED + WearConstants.BATCH);
                    dataMap.getDataMap().putDataMapArrayList(WearConstants.DATA_ARRAY, dataMapsCopy);
                    Wearable.DataApi.putDataItem(mApiClient, dataMap.asPutDataRequest()).setResultCallback(new ResultCallback() {
                        @Override
                        public void onResult(DataApi.DataItemResult dataItemResult) {
                            Log.d(TAG, "Sending sensor data: " + dataItemResult.getStatus().isSuccess());
                        }
                    });
                }
            };
    
            Thread thread = new Thread(runnable);
            thread.start();
        }