STMicroelectronics / BlueSTSDK_Android

Bluetooth low energy Sensors Technology Software Development Kit (Android version)
https://www.st.com/en/embedded-software/bluest-sdk.html
BSD 3-Clause "New" or "Revised" License
92 stars 46 forks source link

Feature-type objects do not receive any data from SensorTile #6

Open cesarev91 opened 7 years ago

cesarev91 commented 7 years ago

Hello Giovanni,

I'm creating an app to monitor a dog's activities through motion, microphone level, and audio features. I have created a unique activity and a single layout where I manage the above features plus the battery.

The battery code is commented because I do not need it right now.

This is the code of the only activity that follows the activity of the node search (ScanActivity): `public class MainActivity extends AppCompatActivity {

/**
 * create an intent for start the activity that will log the information from the node
 *
 * @param c    context used for create the intent
 * @param node note that will be used by the activity
 * @return intent for start this activity
 */
public static Intent getStartIntent(Context c, @NonNull Node node) {
    Intent i = new Intent(c, MainActivity.class);
    i.putExtra(NODE_TAG, node.getTag());
    i.putExtras(NodeContainerFragment.prepareArguments(node));
    return i;
}

private final static String NODE_FRAGMENT = MainActivity.class.getCanonicalName() + "" +
        ".NODE_FRAGMENT";
private final static String NODE_TAG = MainActivity.class.getCanonicalName() + "" +
        ".NODE_TAG";

/** fragment used for keep the connection open */
private NodeContainerFragment mNodeContainer;

/**
 * nodo che mostrerà i dati
 */
private Node mNode;

// Feature on which to apply the listener
private FeatureActivity mfeatureAct;

private FeatureMicLevel mMicLevel;

//private FeatureBattery mBattery;

private FeatureAudioADPCM mAudio;

// feature where we read the audio sync values
private FeatureAudioADPCMSync mAudioSync;

//  Audio track builder
private AudioTrack mAudioTrack;

// The sampling rate
private static final int SAMPLE_RATE = 8000;

//object containing the sync data needed in a ADPCM stream decoding
private BVAudioSyncManager mBVAudioSyncManager = new BVAudioSyncManager();

// audio manager
private static final int AUDIO_STREAM = AudioManager.STREAM_MUSIC;

private boolean mIsRecording;

private AudioBuffer mRecordedAudio;

private static final int MAX_RECORDING_TIME_S = 30;

/**
 * listner FeatureActivity and FeatureMicLevel
 */
FeatureActivity.ActivityType event;
public final Feature.FeatureListener mfeatureRecognListner = new Feature.FeatureListener(){
    @Override
    public void onUpdate(Feature f, Feature.Sample sample) {
        if (f.getName().equals("Activity Recognition")) {
            event = FeatureActivity.getActivityStatus(sample);
        }
    }//onUpdate
};//FeatureActivityRecognitionListner
byte levelMic;
public Feature.FeatureListener mMicLevelListner = new Feature.FeatureListener(){
    @Override
    public void onUpdate(Feature f, Feature.Sample sample) {
        if (f.getName().equals("Mic Level")){
            levelMic = FeatureMicLevel.getMicLevel(sample,1); ///DUBBIO
        }
        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {

                if ((event.equals(FeatureActivity.ActivityType.STATIONARY) || event.equals(FeatureActivity.ActivityType.WALKING)) &&
                        levelMic < 60) {
                    mStatusImage.setImageResource(R.drawable.cane_zen);
                    mStatusText.setText("Calm");
                    mStatusText.setBackgroundColor(Color.GREEN);
                }
                // quando abbaia più di 6 volte in 10 sec, il cane è nervoso
                int count = 0;
                if (levelMic > 100) {
                    count++;
                    for (int i = 0; i == 10; i++) {
                        if (levelMic > 100) {
                            count++;
                            if (count > 6) {
                                mStatusImage.setImageResource(R.drawable.cane_nervoso);
                                mStatusText.setText("Nervous");
                                mStatusText.setBackgroundColor(Color.RED);
                            }
                        }
                    }
                }
                else if (levelMic >= 60 && levelMic <= 100) {
                    mStatusImage.setImageResource(R.drawable.cane_giocoso);
                    mStatusText.setText("Playful");
                    mStatusText.setBackgroundColor(Color.YELLOW);
                }
            }
        });
    }//onUpdate
};//FeatureMicLevelListner

 //    /**
//     * listner FeatureBattery
//     */
//    float levelBat;
//    public final Feature.FeatureListener mBatteryListner = new Feature.FeatureListener() {
//        @Override
//        public void onUpdate(Feature f, Feature.Sample sample){
//            if (f.getName().equals("Battery")) {
//                levelBat = FeatureBattery.getBatteryLevel(sample);
//
//                MainActivity.this.runOnUiThread(new Runnable() {
//                    @Override
//                    public void run() {
//
//                        if(levelBat == 0.0){
//                            mBatteryImage.setImageResource(R.drawable.battery_00);
//                            mBatteryText.setText("Low battery");
//                        }
//                        if(levelBat == 20.0){
//                            mBatteryImage.setImageResource(R.drawable.battery_20);
//                            mBatteryText.setText("Battery about to die");
//                        }
//                        if(levelBat == 40.0){
//                            mBatteryImage.setImageResource(R.drawable.battery_40);
//                            mBatteryText.setText("40%");
//                        }
//                        if(levelBat == 60.0){
//                            mBatteryImage.setImageResource(R.drawable.battery_60);
//                            mBatteryText.setText("60%");
//                        }
//                        if(levelBat == 80.0){
//                            mBatteryImage.setImageResource(R.drawable.battery_80);
//                            mBatteryText.setText("80%");
//                        }
//                        if(levelBat == 100.0){
//                            mBatteryImage.setImageResource(R.drawable.battery_100);
//                            mBatteryText.setText("Battery charged");
//                        }
//
//                    }
//                });
//
//            }
//        }
//
//    };

/**
 * listener for the audio feature, it will updates the audio values
 */
public final Feature.FeatureListener mAudioListener = new Feature.FeatureListener() {

    @Override
    public void onUpdate(final Feature f, final Feature.Sample sample) {
        short[] audioSample = FeatureAudioADPCM.getAudio(sample);

        /* Write audio data for playback
         *    @param short : The array that contains the data for playback
         *    @param int: offset in rawAudio where playback data begins
         *    @param int: The number of shorts to read in rawAudio after the offset
         */
        mAudioTrack.write(audioSample,0,audioSample.length);

    }

};

/**
 * listener for the audioSync feature, it will update the synchronism values
 */
public final Feature.FeatureListener mAudioSyncListener = new Feature.FeatureListener() {
    @Override
    public void onUpdate(Feature f, final Feature.Sample sample) {
        if(mBVAudioSyncManager!=null){
            mBVAudioSyncManager.setSyncParams(sample);
        }
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ImageView mStatusImage;
TextView mStatusText;
ImageView mBatteryImage;
TextView mBatteryText;
Button mPlayButton;
Button mStopButton;
SeekBar mVolumeBar;
FloatingActionButton mRecordButton;
ProgressBar mRecordBar;
AudioManager mAudioManager;
private TextView mRequestStatus;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // find the node.
    String nodeTag = getIntent().getStringExtra(NODE_TAG);
    mNode = Manager.getSharedInstance().getNodeWithTag(nodeTag);

    //create/recover the NodeContainerFragment (DebugConsoleActivity.java)
    if (savedInstanceState == null) {
        Intent i = getIntent();
        mNodeContainer = new NodeContainerFragment();
        mNodeContainer.setArguments(i.getExtras());

        getFragmentManager().beginTransaction()
                .add(mNodeContainer, NODE_FRAGMENT).commit();

    } else {
        mNodeContainer = (NodeContainerFragment) getFragmentManager()
                .findFragmentByTag(NODE_FRAGMENT);
    }//if-else

    mfeatureAct = mNode.getFeature(FeatureActivity.class);
    mMicLevel = mNode.getFeature(FeatureMicLevel.class);
    //mBattery = mNode.getFeature(FeatureBattery.class);
    mAudio = mNode.getFeature(FeatureAudioADPCM.class);
    mAudioSync = mNode.getFeature(FeatureAudioADPCMSync.class);

    //builder audio track
    mAudioTrack = new AudioTrack(
            AudioManager.STREAM_MUSIC,
            SAMPLE_RATE,
            AudioFormat.CHANNEL_OUT_MONO,
            AudioFormat.ENCODING_PCM_16BIT,
            FeatureAudioADPCM.AUDIO_PACKAGE_SIZE,
            AudioTrack.MODE_STREAM);

    mStatusImage = (ImageView)findViewById(R.id.statusImage);
    mStatusText = (TextView)findViewById(R.id.statusText);
    mBatteryImage = (ImageView)findViewById(R.id.batteryImage);
    mBatteryText = (TextView)findViewById(R.id.batteryText);
    mPlayButton = (Button) findViewById(R.id.playButton);
    mStopButton = (Button) findViewById(R.id.stopButton);
    mVolumeBar = (SeekBar)findViewById(R.id.volumeBar);
    mRecordBar = (ProgressBar) findViewById(R.id.recordTimeValue);
    mRecordBar.setIndeterminate(false);
    mRecordButton = (FloatingActionButton) findViewById(R.id.recordButton);
    mRequestStatus = (TextView) findViewById(R.id.requestStatus);

    //  When the play button is pressed
    mPlayButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            mAudioTrack.play();
            mAudioManager.setStreamVolume(AUDIO_STREAM,mVolumeBar.getProgress(),0);

        }
    });

    //When the stop button is pressed
    mStopButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            stopAudioTrack();
            mAudioManager.setStreamVolume(AUDIO_STREAM,0,0);

        }
    });

    //enable control volume
    setVolumeControlStream(AudioManager.STREAM_MUSIC);
    initControls();

}

private void stopAudioTrack(){
    synchronized(this) {
        mAudioTrack.pause();
        mAudioTrack.flush();
    }
}

//   Volume control from SeekBar
private void initControls()
{
    try
    {
        mVolumeBar = (SeekBar)findViewById(R.id.volumeBar);
        mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
        mVolumeBar.setMax(mAudioManager
                .getStreamMaxVolume(AudioManager.STREAM_MUSIC));
        mVolumeBar.setProgress(mAudioManager
                .getStreamVolume(AudioManager.STREAM_MUSIC));

        mVolumeBar.setOnSeekBarChangeListener(new  SeekBar.OnSeekBarChangeListener()
        {
            @Override
            public void onStopTrackingTouch(SeekBar arg0)
            {
            }

            @Override
            public void onStartTrackingTouch(SeekBar arg0)
            {
            }

            @Override
            public void onProgressChanged(SeekBar arg0, int progress, boolean arg2)
            {
                mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
                        progress, 0);
            }
        });
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

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

    // Feature Activity Listner
    mfeatureAct.addFeatureListener(mfeatureRecognListner);
    mNode.enableNotification(mfeatureAct);
    mNode.readFeature(mfeatureAct);
    // Feature MicLevel Listner
    mMicLevel.addFeatureListener(mMicLevelListner);
    mNode.enableNotification(mMicLevel);
    mNode.readFeature(mMicLevel);
    // Feature Battery Listner
//        mBattery.addFeatureListener(mBatteryListner);
//        mNode.enableNotification(mBattery);
//        mNode.readFeature(mBattery);
    // Features Audio Listner
    if(mAudio!=null && mAudioSync!=null) {
        mAudio.addFeatureListener(mAudioListener);
        mBVAudioSyncManager.reinitResetFlag();
        mAudio.setAudioSyncManager(mBVAudioSyncManager);
        mNode.enableNotification(mAudio);
        mAudioSync.addFeatureListener(mAudioSyncListener);
        mNode.enableNotification(mAudioSync);
    }
}

@Override
public void onPause() {
    super.onPause();
    // Feature Activity Listner
    mfeatureAct.removeFeatureListener(mfeatureRecognListner);
    mNode.disableNotification(mfeatureAct);
    // Feature MicLevel Listner
    mMicLevel.removeFeatureListener(mMicLevelListner);
    mNode.disableNotification(mMicLevel);
    // Feature Battery Listner
//        mBattery.removeFeatureListener(mBatteryListner);
//        mNode.disableNotification(mBattery);
    // Features Audio Listner
    if(mAudio!=null) {
        mAudio.removeFeatureListener(mAudioListener);
        mNode.disableNotification(mAudio);
    }
    if(mAudioSync!=null) {
        mAudioSync.removeFeatureListener(mAudioSyncListener);
        mNode.disableNotification(mAudioSync);
    }

}`
GiovanniVisentiniST commented 7 years ago

The node connection is done inside the NodeContainerFragment, so you can't be secure about when it starts and when the connection is done.

Are you secure that the node is connected when the onResume method is celled?

Try to implementa a logic like this one: FeatureListActivity#onResume

Giovanni

cesarev91 commented 7 years ago

Ciao Giovanni,

I tried how you told me and you were right the knot was not connected. But now I have a problem with interacting more features on a single activity. My layout is unique and is handled with a single activity on which I elaborate the data of all the feature. Microphone and Activity Recognition combined to return the animal's status. Battery to handle the battery of SensorTile and AudioADPCM and ADPCMSync to play audio. I tried to keep the features to read the dog's status and it works, but trying to enable ADPCM audio also the node disconnects and the app crashes Do you think it's a problem to handle everything on a single activity, or can you do it?

Cesare

GiovanniVisentiniST commented 7 years ago

Ciao Cesare,

Do you have some error before the app crashes? The possible problem could be that the audio transmit a lot of data and enabling also the other features could freeze the system.

Giovanni

cesarev91 commented 7 years ago

I have to try to reactivate audio features and see if it hangs. At the moment I'm trying to use microphone and activity in a combination and work, that is, they come into one of the conditions I've created and make a change of image. I've created two textview so you can read the event and the microphone level in real time. I do not understand why both of them are set continuously on ERROR (event) and -128 (level).

This is the code at the moment: `public class MainActivity extends AppCompatActivity {

/**
 * create an intent for start the activity that will log the information from the node
 *
 * @param c    context used for create the intent
 * @param node note that will be used by the activity
 * @return intent for start this activity
 */
public static Intent getStartIntent(Context c, @NonNull Node node) {
    Intent i = new Intent(c, MainActivity.class);
    i.putExtra(NODE_TAG, node.getTag());
    i.putExtras(NodeContainerFragment.prepareArguments(node));
    return i;
}

private final static String NODE_FRAGMENT = MainActivity.class.getCanonicalName() + "" +
        ".NODE_FRAGMENT";
private final static String NODE_TAG = MainActivity.class.getCanonicalName() + "" +
        ".NODE_TAG";

/** fragment used for keep the connection open */
private NodeContainerFragment mNodeContainer;

/**
 * nodo che mostrerà i dati
 */
private Node mNode;

// Feature on which to apply the listener
private FeatureActivity mfeatureAct;

private FeatureMicLevel mMicLevel;

//private FeatureBattery mBattery;

private FeatureAudioADPCM mAudio;

// feature where we read the audio sync values
private FeatureAudioADPCMSync mAudioSync;

//  Audio track builder
private AudioTrack mAudioTrack;

// The sampling rate
private static final int SAMPLE_RATE = 8000;

//object containing the sync data needed in a ADPCM stream decoding
private BVAudioSyncManager mBVAudioSyncManager = new BVAudioSyncManager();

// audio manager
private static final int AUDIO_STREAM = AudioManager.STREAM_MUSIC;

private boolean mIsRecording;

private AudioBuffer mRecordedAudio;
//private AudioRecord mRecordedAudio;

private static final int MAX_RECORDING_TIME_S = 30;

/**
 * listener that will be used for enable the notification when the node is connected
 */
public Node.NodeStateListener mNodeStatusListener = new Node.NodeStateListener() {
    @Override
    public void onStateChange(final Node node, final Node.State newState, final Node.State prevState) {
        if (newState == Node.State.Connected) {
            MainActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // Feature Activity Listener
                    mfeatureAct.addFeatureListener(mListeners);
                    mNode.enableNotification(mfeatureAct);
                    //mNode.readFeature(mfeatureAct);
                    // Feature MicLevel Listener
                    mMicLevel.addFeatureListener(mListeners);
                    mNode.enableNotification(mMicLevel);
                    mNode.readFeature(mMicLevel);
                    // Feature Battery Listener
            //        mBattery.addFeatureListener(mBatteryListner);
            //        mNode.enableNotification(mBattery);
            //        mNode.readFeature(mBattery);

                }//run
            });
        }//if

    }//onStateChange
};

TextView eventText;
TextView levelText;

public final Feature.FeatureListener mListeners = new Feature.FeatureListener() {
    @Override
    public void onUpdate(Feature f, Feature.Sample sample) {
        final FeatureActivity.ActivityType event = FeatureActivity.getActivityStatus(sample);
        final byte levelMic = FeatureMicLevel.getMicLevel(sample,1);

        if(event!=null){
            MainActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {

                    eventText.setText("Event:"+event);
                    levelText.setText("MicLevel:"+levelMic);

                    if ((event.equals(FeatureActivity.ActivityType.STATIONARY))&& levelMic < 30) {
                        mStatusImage.setImageResource(R.drawable.cane_zen);
                        mStatusText.setText("Calm");
                        mStatusText.setBackgroundColor(Color.GREEN);
                    }

                    else if(event.equals(FeatureActivity.ActivityType.WALKING)&& levelMic>35){
                        mStatusImage.setImageResource(R.drawable.cane_nervoso);
                        mStatusText.setText("Nervous");
                        mStatusText.setBackgroundColor(Color.RED);

                    }
                    else if (event.equals(FeatureActivity.ActivityType.JOGGING) && (levelMic>=30&&levelMic<=35)) {
                        mStatusImage.setImageResource(R.drawable.cane_giocoso);
                        mStatusText.setText("Playful");
                        mStatusText.setBackgroundColor(Color.YELLOW);
                    }
                }
            });
        }
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ImageView mStatusImage;
TextView mStatusText;
ImageView mBatteryImage;
TextView mBatteryText;
Button mPlayButton;
Button mStopButton;
SeekBar mVolumeBar;
FloatingActionButton mRecordButton;
ProgressBar mRecordBar;
AudioManager mAudioManager;
private TextView mRequestStatus;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // find the node.
    String nodeTag = getIntent().getStringExtra(NODE_TAG);
    mNode = Manager.getSharedInstance().getNodeWithTag(nodeTag);

    //create/recover the NodeContainerFragment (DebugConsoleActivity.java)
    if (savedInstanceState == null) {
        Intent i = getIntent();
        mNodeContainer = new NodeContainerFragment();
        mNodeContainer.setArguments(i.getExtras());

        getFragmentManager().beginTransaction()
                .add(mNodeContainer, NODE_FRAGMENT).commit();

    } else {
        mNodeContainer = (NodeContainerFragment) getFragmentManager()
                .findFragmentByTag(NODE_FRAGMENT);
    }//if-else

    mfeatureAct = mNode.getFeature(FeatureActivity.class);
    mMicLevel = mNode.getFeature(FeatureMicLevel.class);
    //mBattery = mNode.getFeature(FeatureBattery.class);
    //mAudio = mNode.getFeature(FeatureAudioADPCM.class);
    //mAudioSync = mNode.getFeature(FeatureAudioADPCMSync.class);

    mStatusImage = (ImageView)findViewById(R.id.statusImage);
    mStatusText = (TextView)findViewById(R.id.statusText);
    mBatteryImage = (ImageView)findViewById(R.id.batteryImage);
    mBatteryText = (TextView)findViewById(R.id.batteryText);
    mPlayButton = (Button) findViewById(R.id.playButton);
    mStopButton = (Button) findViewById(R.id.stopButton);
    mVolumeBar = (SeekBar)findViewById(R.id.volumeBar);
    mRecordBar = (ProgressBar) findViewById(R.id.recordTimeValue);
    mRecordBar.setIndeterminate(false);
    mRecordButton = (FloatingActionButton) findViewById(R.id.recordButton);
    mRequestStatus = (TextView) findViewById(R.id.requestStatus);
    eventText = (TextView)findViewById(R.id.eventText);
    levelText = (TextView)findViewById(R.id.levelText);

}

@Override
public void onResume() {
    super.onResume();
    mNode.addNodeStateListener(mNodeStatusListener);

}

@Override
public void onPause() {
    super.onPause();
    mNode.removeNodeStateListener(mNodeStatusListener);
}

}`

GiovanniVisentiniST commented 7 years ago

public void onUpdate(Feature f, Feature.Sample sample) { final FeatureActivity.ActivityType event = FeatureActivity.getActivityStatus(sample); final byte levelMic = FeatureMicLevel.getMicLevel(sample,1);

I don't know it the problem is this, but for secure you can't call both the getActivityStatusand getMicLevelpassing the same sample object, because a sample contains the activity OR the micLevel.. so one of the two call is giving you an error code.. Check the feature type using instanceof or create 2 different listener.

cesarev91 commented 7 years ago

I tried with two different listeners and it works, there was also a mistake in getMicLevel (), it was put 0 in place of 1, so I can even read the microphone level and there is no more -128. Then I also activated the whole part to handle the audio but unfortunately nothing works even if it does not hang up, just do not give me any data. I noticed that she does not enter the listener of the audio part. By activating only the audio part and disabling the dog's state, the audio is working. I'm not sure but managing too much data in an activity brings the app into confusion. What do you think about it?

Current code:

 `public class MainActivity extends AppCompatActivity {

/**
 * create an intent for start the activity that will log the information from the node
 *
 * @param c    context used for create the intent
 * @param node note that will be used by the activity
 * @return intent for start this activity
 */
public static Intent getStartIntent(Context c, @NonNull Node node) {
    Intent i = new Intent(c, MainActivity.class);
    i.putExtra(NODE_TAG, node.getTag());
    i.putExtras(NodeContainerFragment.prepareArguments(node));
    return i;
}

private final static String NODE_FRAGMENT = MainActivity.class.getCanonicalName() + "" +
        ".NODE_FRAGMENT";
private final static String NODE_TAG = MainActivity.class.getCanonicalName() + "" +
        ".NODE_TAG";

/** fragment used for keep the connection open */
private NodeContainerFragment mNodeContainer;

/**
 * nodo che mostrerà i dati
 */
private Node mNode;

// Feature on which to apply the listener
private FeatureActivity mfeatureAct;

private FeatureMicLevel mMicLevel;

//private FeatureBattery mBattery;

private FeatureAudioADPCM mAudio;

// feature where we read the audio sync values
private FeatureAudioADPCMSync mAudioSync;

//  Audio track builder
private AudioTrack mAudioTrack;

// The sampling rate
private static final int SAMPLE_RATE = 8000;

//object containing the sync data needed in a ADPCM stream decoding
private BVAudioSyncManager mBVAudioSyncManager = new BVAudioSyncManager();

// audio manager
private static final int AUDIO_STREAM = AudioManager.STREAM_MUSIC;

private boolean mIsRecording;

private AudioBuffer mRecordedAudio;
//private AudioRecord mRecordedAudio;

private static final int MAX_RECORDING_TIME_S = 30;

/**
 * listener that will be used for enable the notification when the node is connected
 */
public Node.NodeStateListener mNodeStatusListener = new Node.NodeStateListener() {
    @Override
    public void onStateChange(final Node node, final Node.State newState, final Node.State prevState) {
        if (newState == Node.State.Connected) {
            MainActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // Feature Activity Listener
                    mfeatureAct.addFeatureListener(mActListener);
                    mNode.enableNotification(mfeatureAct);
                    //mNode.readFeature(mfeatureAct);
                    // Feature MicLevel Listener
                    mMicLevel.addFeatureListener(mMicListener);
                    mNode.enableNotification(mMicLevel);
                    mNode.readFeature(mMicLevel);
                    // Feature Battery Listener
            //        mBattery.addFeatureListener(mBatteryListner);
            //        mNode.enableNotification(mBattery);
            //        mNode.readFeature(mBattery);

                    // Features Audio Listener
                    mAudio.addFeatureListener(mAudioListener);
                    mBVAudioSyncManager.reinitResetFlag();
                    mAudio.setAudioSyncManager(mBVAudioSyncManager);
                    mNode.enableNotification(mAudio);
                    mAudioSync.addFeatureListener(mAudioSyncListener);
                    mNode.enableNotification(mAudioSync);

                }//run
            });
        }//if

    }//onStateChange
};

TextView eventText;
TextView levelText;

FeatureActivity.ActivityType event;
public final Feature.FeatureListener mActListener = new Feature.FeatureListener() {
    @Override
    public void onUpdate(Feature f, Feature.Sample sample) {
        event = FeatureActivity.getActivityStatus(sample);
        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                eventText.setText("Event:"+event);
            }
        });
        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if ((event.equals(FeatureActivity.ActivityType.STATIONARY)||event.equals(FeatureActivity.ActivityType.WALKING))&& levelMic < 30) {
                    mStatusImage.setImageResource(R.drawable.cane_zen);
                    mStatusText.setText("Calm");
                    mStatusText.setBackgroundColor(Color.GREEN);
                }
                else if (event.equals(FeatureActivity.ActivityType.FASTWALKING)&& levelMic > 50){
                    mStatusImage.setImageResource(R.drawable.cane_nervoso);
                    mStatusText.setText("Nervous");
                    mStatusText.setBackgroundColor(Color.RED);
                }
                else if(event.equals(FeatureActivity.ActivityType.JOGGING)){
                    mStatusImage.setImageResource(R.drawable.cane_giocoso);
                    mStatusText.setText("Playful");
                    mStatusText.setBackgroundColor(Color.YELLOW);
                }

            }
        });
    }
};
byte levelMic;
public final Feature.FeatureListener mMicListener = new Feature.FeatureListener() {
    @Override
    public void onUpdate(Feature f, Feature.Sample sample) {
        levelMic = FeatureMicLevel.getMicLevel(sample,0);
        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if(levelMic > 0 && levelMic < 128){
                    levelText.setText("MicLevel:"+levelMic);
                }

            }
        });

    }
};

/**
 * listener for the audio feature, it will updates the audio values
 */
public final Feature.FeatureListener mAudioListener = new Feature.FeatureListener() {

    @Override
    public void onUpdate(final Feature f, final Feature.Sample sample) {
        short[] audioSample = FeatureAudioADPCM.getAudio(sample);

        /* Write audio data for playback
         *    @param short : The array that contains the data for playback
         *    @param int: offset in rawAudio where playback data begins
         *    @param int: The number of shorts to read in rawAudio after the offset
         */
        mAudioTrack.write(audioSample,0,audioSample.length);

    }

};

/**
 * listener for the audioSync feature, it will update the synchronism values
 */
public final Feature.FeatureListener mAudioSyncListener = new Feature.FeatureListener() {
    @Override
    public void onUpdate(Feature f, final Feature.Sample sample) {
        if(mBVAudioSyncManager!=null){
            mBVAudioSyncManager.setSyncParams(sample);
        }
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ImageView mStatusImage;
TextView mStatusText;
ImageView mBatteryImage;
TextView mBatteryText;
Button mPlayButton;
Button mStopButton;
SeekBar mVolumeBar;
FloatingActionButton mRecordButton;
ProgressBar mRecordBar;
AudioManager mAudioManager;
private TextView mRequestStatus;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // find the node.
    String nodeTag = getIntent().getStringExtra(NODE_TAG);
    mNode = Manager.getSharedInstance().getNodeWithTag(nodeTag);

    //create/recover the NodeContainerFragment (DebugConsoleActivity.java)
    if (savedInstanceState == null) {
        Intent i = getIntent();
        mNodeContainer = new NodeContainerFragment();
        mNodeContainer.setArguments(i.getExtras());

        getFragmentManager().beginTransaction()
                .add(mNodeContainer, NODE_FRAGMENT).commit();

    } else {
        mNodeContainer = (NodeContainerFragment) getFragmentManager()
                .findFragmentByTag(NODE_FRAGMENT);
    }//if-else

    mfeatureAct = mNode.getFeature(FeatureActivity.class);
    mMicLevel = mNode.getFeature(FeatureMicLevel.class);
    //mBattery = mNode.getFeature(FeatureBattery.class);
    mAudio = mNode.getFeature(FeatureAudioADPCM.class);
    mAudioSync = mNode.getFeature(FeatureAudioADPCMSync.class);

    //builder audio track
    mAudioTrack = new AudioTrack(
            AudioManager.STREAM_MUSIC,
            SAMPLE_RATE,
            AudioFormat.CHANNEL_OUT_MONO,
            AudioFormat.ENCODING_PCM_16BIT,
            FeatureAudioADPCM.AUDIO_PACKAGE_SIZE,
            AudioTrack.MODE_STREAM);

    mStatusImage = (ImageView)findViewById(R.id.statusImage);
    mStatusText = (TextView)findViewById(R.id.statusText);
    mBatteryImage = (ImageView)findViewById(R.id.batteryImage);
    mBatteryText = (TextView)findViewById(R.id.batteryText);
    mPlayButton = (Button) findViewById(R.id.playButton);
    mStopButton = (Button) findViewById(R.id.stopButton);
    mVolumeBar = (SeekBar)findViewById(R.id.volumeBar);
    mRecordBar = (ProgressBar) findViewById(R.id.recordTimeValue);
    mRecordBar.setIndeterminate(false);
    mRecordButton = (FloatingActionButton) findViewById(R.id.recordButton);
    mRequestStatus = (TextView) findViewById(R.id.requestStatus);
    eventText = (TextView)findViewById(R.id.eventText);
    levelText = (TextView)findViewById(R.id.levelText);

    //  When the play button is pressed
    mPlayButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            mAudioTrack.play();
            mAudioManager.setStreamVolume(AUDIO_STREAM,mVolumeBar.getProgress(),0);

        }
    });

    //When the stop button is pressed
    mStopButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            stopAudioTrack();
            mAudioManager.setStreamVolume(AUDIO_STREAM,0,0);

        }
    });

    //enable control volume
    setVolumeControlStream(AudioManager.STREAM_MUSIC);
    initControls();

}

private void stopAudioTrack(){
    synchronized(this) {
        mAudioTrack.pause();
        mAudioTrack.flush();
    }
}

//   Volume control from SeekBar
private void initControls()
{
    try
    {
        mVolumeBar = (SeekBar)findViewById(R.id.volumeBar);
        mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
        mVolumeBar.setMax(mAudioManager
                .getStreamMaxVolume(AudioManager.STREAM_MUSIC));
        mVolumeBar.setProgress(mAudioManager
                .getStreamVolume(AudioManager.STREAM_MUSIC));

        mVolumeBar.setOnSeekBarChangeListener(new  SeekBar.OnSeekBarChangeListener()
        {
            @Override
            public void onStopTrackingTouch(SeekBar arg0)
            {
            }

            @Override
            public void onStartTrackingTouch(SeekBar arg0)
            {
            }

            @Override
            public void onProgressChanged(SeekBar arg0, int progress, boolean arg2)
            {
                mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
                        progress, 0);
            }
        });
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

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

        mNode.addNodeStateListener(mNodeStatusListener);

}

@Override
public void onPause() {
    super.onPause();

    mNode.removeNodeStateListener(mNodeStatusListener);
}

} `

cesarev91 commented 7 years ago

Ciao Giovanni,

I've changed the way I work, because managing a lot of data on a single activity does not allow the app to work Now I'm using three activities and three layouts, I've also created an activity that shows the features (status, audio, battery). ScanActivity -> FunctionActivity -> StatusActivity, AudioActivity, BatteryActivity The app starts without errors but I do not receive any data. This is the StatusActivity class: `public class StatusActivity extends AppCompatActivity {

/**
 * create an intent for start the activity that will log the information from the node
 *
 * @param c    context used for create the intent
 * @param node note that will be used by the activity
 * @return intent for start this activity
 */
public static Intent getStartIntent(Context c, @NonNull Node node) {
    Intent i = new Intent(c, StatusActivity.class);
    i.putExtra(NODE_TAG, node.getTag());
    i.putExtras(NodeContainerFragment.prepareArguments(node));
    return i;
}

private final static String NODE_TAG = StatusActivity.class.getCanonicalName() + "" +
        ".NODE_TAG";
private final static String NODE_FRAGMENT = StatusActivity.class.getCanonicalName() + "" +
        ".NODE_FRAGMENT";

/** fragment used for keep the connection open */
private NodeContainerFragment mNodeContainer;

/**
 * nodo che mostrerà i dati
 */
private Node mNode;

// Feature on which to apply the listener
private FeatureActivity mActivity;

private FeatureMicLevel mMicLevel;

/**
 * listener that will be used for enable the notification when the node is connected
 */
public Node.NodeStateListener mNodeStatusListener = new Node.NodeStateListener() {
            @Override
            public void onStateChange(final Node node, final Node.State newState, final Node.State prevState) {
                if (newState == Node.State.Connected) {
                    StatusActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // Feature Activity Listener
                            mActivity.addFeatureListener(mActListener);
                            mNode.enableNotification(mActivity);
                            mNode.readFeature(mActivity);
                            // Feature MicLevel Listener
                            mMicLevel.addFeatureListener(mMicListener);
                            mNode.enableNotification(mMicLevel);
                            mNode.readFeature(mMicLevel);

                        }//run
                    });
                }//if

            }//onStateChange
        };

TextView mEventText;
TextView mLevelText;

FeatureActivity.ActivityType event;
public Feature.FeatureListener mActListener = new Feature.FeatureListener() {
    @Override
    public void onUpdate(Feature f, Feature.Sample sample) {
        if(f.getName().equals("Activity Recognition")){
            event = FeatureActivity.getActivityStatus(sample);
            StatusActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mEventText.setText("Event:"+event);
                }
            });
        }
        StatusActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if ((event.equals(FeatureActivity.ActivityType.STATIONARY)||event.equals(FeatureActivity.ActivityType.WALKING))&& levelMic < 30) {
                    mStatusImage.setImageResource(R.drawable.cane_zen);
                    mStatusText.setText("Calm");
                    mStatusText.setBackgroundColor(Color.GREEN);
                }
                else if (event.equals(FeatureActivity.ActivityType.FASTWALKING)&& levelMic > 50){
                    mStatusImage.setImageResource(R.drawable.cane_nervoso);
                    mStatusText.setText("Nervous");
                    mStatusText.setBackgroundColor(Color.RED);
                }
                else if(event.equals(FeatureActivity.ActivityType.JOGGING)){
                    mStatusImage.setImageResource(R.drawable.cane_giocoso);
                    mStatusText.setText("Playful");
                    mStatusText.setBackgroundColor(Color.YELLOW);
                }

            }
        });
    }
};
byte levelMic;
public Feature.FeatureListener mMicListener = new Feature.FeatureListener() {
    @Override
    public void onUpdate(Feature f, Feature.Sample sample) {
        if(f.getName().equals("Mic Level")){
            levelMic = FeatureMicLevel.getMicLevel(sample,0);
            StatusActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if(levelMic > 0 && levelMic <= 128){
                        mLevelText.setText("MicLevel:"+levelMic);
                    }

                }
            });
        }

    }
};

ImageView mStatusImage;
TextView mStatusText;

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

    // find the node.
    String nodeTag = getIntent().getStringExtra(NODE_TAG);
    mNode = Manager.getSharedInstance().getNodeWithTag(nodeTag);

    //create/recover the NodeContainerFragment
    if (savedInstanceState == null) {
        Intent i = getIntent();
        mNodeContainer = new NodeContainerFragment();
        mNodeContainer.setArguments(i.getExtras());
        getFragmentManager().beginTransaction()
                .add(mNodeContainer, NODE_FRAGMENT).commit();
    } else {
        mNodeContainer = (NodeContainerFragment) getFragmentManager()
                .findFragmentByTag(NODE_FRAGMENT);
    }//if-else

    mActivity = mNode.getFeature(FeatureActivity.class);
    mMicLevel = mNode.getFeature(FeatureMicLevel.class);

    mStatusImage = (ImageView)findViewById(R.id.statusImage);
    mStatusText = (TextView)findViewById(R.id.statusText);

    mEventText = (TextView)findViewById(R.id.eventText);
    mLevelText = (TextView)findViewById(R.id.mic_levelText);

}

@Override
public void onResume() {
    super.onResume();
    mNode.addNodeStateListener(mNodeStatusListener);

}

@Override
public void onPause() {
    super.onPause();
    mNode.removeNodeStateListener(mNodeStatusListener);

}

/**
 * if we have to leave this activity, we force to keep the connection open, since we go back
 * in the {@link FunctionsActivity}
 *
 */
@Override
public void onBackPressed() {
    mNodeContainer.keepConnectionOpen(true);
    super.onBackPressed();
}//onBackPressed

} `

cesarev91 commented 7 years ago

How do I keep the node connected during the operation of each activity?

GiovanniVisentiniST commented 7 years ago

Note that if the node is already connected your activity will not work, since you will not receive the connection event. Please see FeatureListActivity#onResume()

The connection is managed inside the NodeContainerFragment, to avoid to close it you have to call mNodeContainer.keepConnectionOpen(true) before start the new activity this will avoid to disconnect the node when the fragment is destroyed see: FeatureListActivity#onOptionsItemSelected()

cesarev91 commented 7 years ago

In the FunctionActivity class when I call other activities I use keepConnectionOpen (true) This is the FunctionActivity class: `public class FunctionsActivity extends AppCompatActivity {

/**
 * create an intent for start the activity that will log the information from the node
 *
 * @param c    context used for create the intent
 * @param node note that will be used by the activity
 * @return intent for start this activity
 */
public static Intent getStartIntent(Context c, @NonNull Node node) {
    Intent i = new Intent(c, FunctionsActivity.class);
    i.putExtra(NODE_TAG, node.getTag());
    i.putExtras(NodeContainerFragment.prepareArguments(node));
    return i;
}

/**
 * tag used for store the node id that permit us to find the node selected by the user
 */
private final static String NODE_TAG = FunctionsActivity.class.getCanonicalName() + "" +
        ".NODE_TAG";
/**
 * tag used for retrieve the NodeContainerFragment
 */
private final static String NODE_FRAGMENT = FunctionsActivity.class.getCanonicalName() + "" +
        ".NODE_FRAGMENT";

/**
 * fragment that manage the node connection and avoid a re connection each time the activity
 * is recreated
 */
private NodeContainerFragment mNodeContainer;

/**
 * node that will stream the data
 */
private Node mNode;

Button statusButton;
Button audioButton;
Button batteryButton;

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

    //find the node
    String nodeTag = getIntent().getStringExtra(NODE_TAG);
    mNode = Manager.getSharedInstance().getNodeWithTag(nodeTag);

 //        Node.State state = mNode.getState();
//        System.out.print("Stato: "+state);

    //create or recover the NodeContainerFragment
    if (savedInstanceState == null) {
        Intent i = getIntent();
        mNodeContainer = new NodeContainerFragment();
        mNodeContainer.setArguments(i.getExtras());

        getFragmentManager().beginTransaction()
                .add(mNodeContainer, NODE_FRAGMENT).commit();

    } else {
        mNodeContainer = (NodeContainerFragment) getFragmentManager()
                .findFragmentByTag(NODE_FRAGMENT);

    }//if-else

    statusButton = (Button)findViewById(R.id.status_button);
    audioButton = (Button)findViewById(R.id.audio_button);
    batteryButton = (Button)findViewById(R.id.battery_button);

    statusButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            mNodeContainer.keepConnectionOpen(true);
            startActivity(StatusActivity.getStartIntent(getApplicationContext(),mNode));
        }
    });

    audioButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            mNodeContainer.keepConnectionOpen(true);
            startActivity(AudioActivity.getStartIntent(getApplicationContext(),mNode));
        }
    });

    batteryButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            mNodeContainer.keepConnectionOpen(true);
            startActivity(BatteryActivity.getStartIntent(getApplicationContext(),mNode));
        }
    });
}

`

GiovanniVisentiniST commented 7 years ago

Usually you pass the current activity as a context, but anyway it seems ok, it is not working? if the keepConnectionOpenis not working please open a new issue..

About your activity that doesn't receive data: Since you split the activity and you have the same problem probably you don't have to much data, but you or the SDK are doing something wrong..

As already told the only weak point that I see is the onResumefunction that will not enable the notification if the node connect before the onResumeis called.

Try to isolate the problem, create an activity that only enable the micLevel, get it works, than add another feature..

maybe you can set a breakpoint into the BluetoothGattCallbacks object to follow all the low level BLE comunication..

cesarev91 commented 7 years ago

Ciao Giovanni,

In the StatusActivity class, I inserted these two lines of code after instantiating mNode, which tell me if the node is connected:

Node.State state = mNode.getState (); System.out.print ("Status:" + state);

The node is connected to the onCreate but I can not get into any of the listeners; the app starts without errors but does not show any data. Now I will try to run MicLevel only.

cesarev91 commented 7 years ago

I tried with this configuration and MicLevel works. But I do get a strange thing when I stop the app from android studio. To do this I need to unplug and reattach the SensorTile usb socket. If not, the app starts but does not show me any data and the SensorTile LED blinks mildly with respect to the first operation

`public class StatusActivity extends AppCompatActivity {

/**
 * create an intent for start the activity that will log the information from the node
 *
 * @param c    context used for create the intent
 * @param node note that will be used by the activity
 * @return intent for start this activity
 */
public static Intent getStartIntent(Context c, @NonNull Node node) {
    Intent i = new Intent(c, StatusActivity.class);
    i.putExtra(NODE_TAG, node.getTag());
    i.putExtras(NodeContainerFragment.prepareArguments(node));
    return i;
}

private final static String NODE_TAG = StatusActivity.class.getCanonicalName() + "" +
        ".NODE_TAG";
private final static String NODE_FRAGMENT = StatusActivity.class.getCanonicalName() + "" +
        ".NODE_FRAGMENT";

/** fragment used for keep the connection open */
private NodeContainerFragment mNodeContainer;

/**
 * nodo che mostrerà i dati
 */
private Node mNode;

// Feature on which to apply the listener
private FeatureActivity mActivity;

private FeatureMicLevel mMicLevel;

/**
 * listener that will be used for enable the notification when the node is connected
 */

TextView mEventText;
TextView mLevelText;

byte levelMic;
public Feature.FeatureListener mMicListener = new Feature.FeatureListener() {
    @Override
    public void onUpdate(Feature f, Feature.Sample sample) {
        if(f.getName().equals("Mic Level")){
            levelMic = FeatureMicLevel.getMicLevel(sample,0);
            StatusActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //if(levelMic > 0 && levelMic <= 128){
                        mLevelText.setText("MicLevel: "+levelMic);
                    //}

                }
            });
        }

    }
};

ImageView mStatusImage;
TextView mStatusText;

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

    // find the node.
    String nodeTag = getIntent().getStringExtra(NODE_TAG);
    mNode = Manager.getSharedInstance().getNodeWithTag(nodeTag);

    Node.State state = mNode.getState();
    System.out.print("Stato: "+state);

    //create/recover the NodeContainerFragment
    if (savedInstanceState == null) {
        Intent i = getIntent();
        mNodeContainer = new NodeContainerFragment();
        mNodeContainer.setArguments(i.getExtras());
        getFragmentManager().beginTransaction()
                .add(mNodeContainer, NODE_FRAGMENT).commit();
    } else {
        mNodeContainer = (NodeContainerFragment) getFragmentManager()
                .findFragmentByTag(NODE_FRAGMENT);
    }//if-else

    //mActivity = mNode.getFeature(FeatureActivity.class);
    mMicLevel = mNode.getFeature(FeatureMicLevel.class);

    mStatusImage = (ImageView)findViewById(R.id.statusImage);
    mStatusText = (TextView)findViewById(R.id.statusText);

    mEventText = (TextView)findViewById(R.id.eventText);
    mLevelText = (TextView)findViewById(R.id.mic_levelText);

}

@Override
public void onResume() {
    super.onResume();
    mMicLevel.addFeatureListener(mMicListener);
    mNode.enableNotification(mMicLevel);

}

@Override
public void onPause() {
    super.onPause();
    mMicLevel.removeFeatureListener(mMicListener);
    mNode.disableNotification(mMicLevel);

}

/**
 * if we have to leave this activity, we force to keep the connection open, since we go back
 * in the {@link FunctionsActivity}
 *
 */
@Override
public void onBackPressed() {
    mNodeContainer.keepConnectionOpen(true);
    super.onBackPressed();
}//onBackPressed

} `

cesarev91 commented 7 years ago

Since every time I make changes I have several issues that do not match the question I asked about github so for any problem I should open a new discussion, if it is good for you to communicate directly in some way?

However, by adding the activity along with the microphone, the app detects both events, even though it sometimes disconnects and stops working.

GiovanniVisentiniST commented 7 years ago

Don't worry open a new GitHub issue, its better have a public discussion to help also other people.

I'm reporting the problem with the Andrioid Studio to my colleges that develop the FW.

For your problem with the micLevel + activity try the example app and see if it happen also with that app.. I try and it works..

PS: your onResume method is still wrong..

cesarev91 commented 7 years ago

Is it wrong to add listeners and enable notifications onResume? In another version of my app I created an activity for each feature and onResume I did this and everything works.

I've always worked on the BlueSTExample module.

At the moment I'm working with both features (MicLevel + Activity) and work together. Problems remain the same: some disconnection during operation and when I stop the app from android studio I have to unplug the usb socket to reboot the app. This is the code:

`public class StatusActivity extends AppCompatActivity {

/**
 * create an intent for start the activity that will log the information from the node
 *
 * @param c    context used for create the intent
 * @param node note that will be used by the activity
 * @return intent for start this activity
 */
public static Intent getStartIntent(Context c, @NonNull Node node) {
    Intent i = new Intent(c, StatusActivity.class);
    i.putExtra(NODE_TAG, node.getTag());
    i.putExtras(NodeContainerFragment.prepareArguments(node));
    return i;
}

private final static String NODE_TAG = StatusActivity.class.getCanonicalName() + "" +
        ".NODE_TAG";
private final static String NODE_FRAGMENT = StatusActivity.class.getCanonicalName() + "" +
        ".NODE_FRAGMENT";

/** fragment used for keep the connection open */
private NodeContainerFragment mNodeContainer;

/**
 * nodo che mostrerà i dati
 */
private Node mNode;

// Feature on which to apply the listener
private FeatureActivity mActivity;

private FeatureMicLevel mMicLevel;

TextView mEventText;
TextView mLevelText;

//FeatureActivity.ActivityType event;
public final Feature.FeatureListener mActListener = new Feature.FeatureListener() {
    @Override
    public void onUpdate(Feature f, Feature.Sample sample) {
        if(f.getName().equals("Activity Recognition")){
            final FeatureActivity.ActivityType event = FeatureActivity.getActivityStatus(sample);
            StatusActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mEventText.setText("Event: "+event);

                    if ((event.equals(FeatureActivity.ActivityType.STATIONARY)||event.equals(FeatureActivity.ActivityType.WALKING))&& levelMic < 30) {
                        mStatusImage.setImageResource(R.drawable.cane_zen);
                        mStatusText.setText("Calm");
                        mStatusText.setBackgroundColor(Color.GREEN);
                    }
                    else if (event.equals(FeatureActivity.ActivityType.FASTWALKING)&& levelMic > 50){
                        mStatusImage.setImageResource(R.drawable.cane_nervoso);
                        mStatusText.setText("Nervous");
                        mStatusText.setBackgroundColor(Color.RED);
                    }
                    else if(event.equals(FeatureActivity.ActivityType.JOGGING)){
                        mStatusImage.setImageResource(R.drawable.cane_giocoso);
                        mStatusText.setText("Playful");
                        mStatusText.setBackgroundColor(Color.YELLOW);
                    }
                }
            });

        }

    }
};
byte levelMic;
public Feature.FeatureListener mMicListener = new Feature.FeatureListener() {
    @Override
    public void onUpdate(Feature f, Feature.Sample sample) {
        if(f.getName().equals("Mic Level")){
            levelMic = FeatureMicLevel.getMicLevel(sample,0);
            StatusActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //if(levelMic > 0 && levelMic <= 128){
                        mLevelText.setText("MicLevel: "+levelMic);
                    //}

                }
            });
        }

    }
};

ImageView mStatusImage;
TextView mStatusText;

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

    // find the node.
    String nodeTag = getIntent().getStringExtra(NODE_TAG);
    mNode = Manager.getSharedInstance().getNodeWithTag(nodeTag);

    Node.State state = mNode.getState();
    System.out.print("Stato: "+state);

    //create/recover the NodeContainerFragment
    if (savedInstanceState == null) {
        Intent i = getIntent();
        mNodeContainer = new NodeContainerFragment();
        mNodeContainer.setArguments(i.getExtras());
        getFragmentManager().beginTransaction()
                .add(mNodeContainer, NODE_FRAGMENT).commit();
    } else {
        mNodeContainer = (NodeContainerFragment) getFragmentManager()
                .findFragmentByTag(NODE_FRAGMENT);
    }//if-else

    mActivity = mNode.getFeature(FeatureActivity.class);
    mMicLevel = mNode.getFeature(FeatureMicLevel.class);

    mStatusImage = (ImageView)findViewById(R.id.statusImage);
    mStatusText = (TextView)findViewById(R.id.statusText);

    mEventText = (TextView)findViewById(R.id.eventText);
    mLevelText = (TextView)findViewById(R.id.mic_levelText);

}

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

    //mNode.addNodeStateListener(mNodeStatusListener);

    mActivity.addFeatureListener(mActListener);
    mNode.enableNotification(mActivity);
    mNode.readFeature(mActivity);
    mMicLevel.addFeatureListener(mMicListener);
    mNode.enableNotification(mMicLevel);

}

@Override
public void onPause() {
    super.onPause();
    //mNode.removeNodeStateListener(mNodeStatusListener);
    mActivity.removeFeatureListener(mActListener);
    mNode.disableNotification(mActivity);
    mMicLevel.removeFeatureListener(mMicListener);
    mNode.disableNotification(mMicLevel);

}

/**
 * if we have to leave this activity, we force to keep the connection open, since we go back
 * in the {@link FunctionsActivity}
 *
 */
@Override
public void onBackPressed() {
    mNodeContainer.keepConnectionOpen(true);
    super.onBackPressed();
}//onBackPressed

} `