com.t2.compassionMeditation.DeviceManagerActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.t2.compassionMeditation.DeviceManagerActivity.java

Source

/*****************************************************************
BioZen
    
Copyright (C) 2011 The National Center for Telehealth and 
Technology
    
Eclipse Public License 1.0 (EPL-1.0)
    
This library is free software; you can redistribute it and/or
modify it under the terms of the Eclipse Public License as
published by the Free Software Foundation, version 1.0 of the 
License.
    
The Eclipse Public License is a reciprocal license, under 
Section 3. REQUIREMENTS iv) states that source code for the 
Program is available from such Contributor, and informs licensees 
how to obtain it in a reasonable manner on or through a medium 
customarily used for software exchange.
    
Post your updates and modifications to our GitHub or email to 
t2@tee2.org.
    
This library is distributed WITHOUT ANY WARRANTY; without 
the implied warranty of MERCHANTABILITY or FITNESS FOR A 
PARTICULAR PURPOSE.  See the Eclipse Public License 1.0 (EPL-1.0)
for more details.
     
You should have received a copy of the Eclipse Public License
along with this library; if not, 
visit http://www.opensource.org/licenses/EPL-1.0
    
*****************************************************************/
package com.t2.compassionMeditation;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Vector;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import spine.SPINEFactory;
import spine.SPINEListener;
import spine.SPINEManager;
import spine.datamodel.Data;
import spine.datamodel.Node;
import spine.datamodel.ServiceMessage;
import spine.datamodel.functions.SpineServiceCommand;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.os.Messenger;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.ToggleButton;

import com.t2.SpineReceiver;
import com.t2.SpineReceiver.BioFeedbackStatus;
import com.t2.SpineReceiver.OnBioFeedbackMessageRecievedListener;
import com.t2.biofeedback.BioFeedbackService;
import com.t2.R;
import com.t2.compassionUtils.BioSensor;
import com.t2.compassionUtils.Util;

/**
 * Activity used to manually administer list of available devices.
 * This is instantiated in two conditions
 *  1. When the user starts the service manually (without, or more accurately before the Spine server).
 *  2. When the user selects "Manage Devices" from the Spine Server main menu.
 *  
 * @author scott.coleman
 *
 */
public class DeviceManagerActivity extends Activity
        implements OnClickListener, SPINEListener, OnBioFeedbackMessageRecievedListener {
    private static final String TAG = "BFDemo";

    private static final int BLUETOOTH_SETTINGS = 987;

    private ListView deviceList;
    private ManagerItemAdapter deviceListAdapter;

    private AlertDialog bluetoothDisabledDialog;
    ArrayList<Messenger> mServerListeners = new ArrayList<Messenger>();
    String mVersionName = "";
    Boolean mBluetoothEnabled;

    protected SharedPreferences sharedPref;

    /**
     * List of all currently PAIRED BioSensors
     */
    private ArrayList<BioSensor> mBioSensors = new ArrayList<BioSensor>();

    /**
     * The Spine manager contains the bulk of the Spine server. 
     */
    private static SPINEManager mSpineManager;

    /**
    * This is a broadcast receiver. Note that this is used ONLY for command/status messages from the AndroidBTService
    * All data from the service goes through the mail SPINE mechanism (received(Data data)).
    */
    private SpineReceiver mCommandReceiver;

    private DeviceManagerActivity mInstance;

    String[] measureNames = { "OPne", "two" };
    boolean toggleArray[] = new boolean[2];

    AlertDialog mParamChooserAlert;

    /**
     * Handles UI button clicks
     * @param v
     */
    public void onButtonClick(final View v) {
        final int id = v.getId();
        switch (id) {

        // Present a list of all parameter types to allow the user
        // to associate a specific device (address) to a specific parameter
        // This association will be used in the main activities so that they
        // know the BT address of particular sensors to tell them to start/stop

        // The associations are stored in Shared pref
        //   key = param name (See R.array.parameter_names)
        //   value = BT address

        case R.id.parameter:
            final String address = (String) v.getTag();
            AlertDialog.Builder alertParamChooser = new AlertDialog.Builder(mInstance);
            alertParamChooser.setTitle("Select parameter for this device");
            //             mParamChooserAlert = alertParamChooser.create();

            alertParamChooser.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                }
            });
            alertParamChooser.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                }
            });
            alertParamChooser.setSingleChoiceItems(R.array.parameter_names, -1,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, final int which) {
                            String[] paramNamesStringArray = getResources().getStringArray(R.array.parameter_names);
                            final String name = paramNamesStringArray[which];

                            // See which pamrameter is associated with this name
                            String device = SharedPref.getDeviceForParam(mInstance, name);
                            if (device != null && which != 0) {
                                AlertDialog.Builder alertWarning = new AlertDialog.Builder(mInstance);
                                String message = String.format(
                                        "Another sensor (%s) currently feeds this parameter. Please change this previous mapping before trying again",
                                        device);
                                alertWarning.setMessage(message);

                                alertWarning.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int whichButton) {
                                        mParamChooserAlert.dismiss();
                                    }

                                });
                                alertWarning.setNegativeButton("Select Anyway",
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface dialog, int whichButton) {
                                                Log.d(TAG, "param name = " + name + ", address = " + address);
                                                if (which != 0) {
                                                    SharedPref.setParamForDevice(mInstance, name, address);
                                                    v.getBackground().setColorFilter(Color.GREEN,
                                                            PorterDuff.Mode.MULTIPLY);
                                                    ((Button) v.findViewById(R.id.parameter)).setText(name);
                                                } else {
                                                    SharedPref.setParamForDevice(mInstance, name, address);
                                                    v.getBackground().setColorFilter(Color.LTGRAY,
                                                            PorterDuff.Mode.MULTIPLY);
                                                    ((Button) v.findViewById(R.id.parameter)).setText("Parameter");

                                                }

                                            }

                                        });

                                alertWarning.show();

                            } else {
                                // The parameter is currently not mapped to a sensor, so we can go ahead and map it
                                Log.d(TAG, "param name = " + name + ", address = " + address);
                                if (which != 0) {
                                    SharedPref.setParamForDevice(mInstance, name, address);
                                    v.getBackground().setColorFilter(Color.GREEN, PorterDuff.Mode.MULTIPLY);
                                    ((Button) v.findViewById(R.id.parameter)).setText(name);
                                } else {
                                    SharedPref.setParamForDevice(mInstance, name, address);
                                    v.getBackground().setColorFilter(Color.LTGRAY, PorterDuff.Mode.MULTIPLY);
                                    ((Button) v.findViewById(R.id.parameter)).setText("Parameter");

                                }
                            }
                        }
                    });
            //            alert.show();   
            mParamChooserAlert = alertParamChooser.create();

            mParamChooserAlert.show();

            break;

        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mInstance = this;
        sharedPref = PreferenceManager.getDefaultSharedPreferences(getBaseContext());

        //this.sendBroadcast(new Intent(BioFeedbackService.ACTION_SERVICE_START));

        this.setContentView(R.layout.device_manager_activity_layout);

        this.findViewById(R.id.bluetoothSettingsButton).setOnClickListener(this);

        Resources resources = this.getResources();
        AssetManager assetManager = resources.getAssets();
        try {
            mSpineManager = SPINEFactory.createSPINEManager("SPINETestApp.properties", resources);
        } catch (InstantiationException e) {
            Log.e(TAG, this.getClass().getSimpleName() + " Exception creating SPINE manager: " + e.toString());
            e.printStackTrace();
        }
        // ... then we need to register a SPINEListener implementation to the SPINE manager instance
        // to receive sensor node data from the Spine server
        // (I register myself since I'm a SPINEListener implementation!)
        mSpineManager.addListener(this);

        // Create a broadcast receiver. Note that this is used ONLY for command messages from the service
        // All data from the service goes through the mail SPINE mechanism (received(Data data)).
        // See public void received(Data data)
        this.mCommandReceiver = new SpineReceiver(this);
        // Set up filter intents so we can receive broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.t2.biofeedback.service.status.BROADCAST");
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        filter.addAction(BioFeedbackService.ACTION_STATUS_BROADCAST);

        this.registerReceiver(this.mCommandReceiver, filter);

        // Tell the bluetooth service to send us a list of bluetooth devices and system status
        // Response comes in public void onStatusReceived(BioFeedbackStatus bfs) STATUS_PAIRED_DEVICES      
        mSpineManager.pollBluetoothDevices();

        //      this.deviceManager = DeviceManager.getInstance(this.getBaseContext(), null);
        this.deviceList = (ListView) this.findViewById(R.id.list);

        this.deviceListAdapter = new ManagerItemAdapter(this, R.layout.manager_item);
        this.deviceList.setAdapter(this.deviceListAdapter);

        this.bluetoothDisabledDialog = new AlertDialog.Builder(this).setMessage("Bluetooth is not enabled.")
                .setOnCancelListener(new OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        finish();
                    }
                }).setPositiveButton("Setup Bluetooth", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        startBluetoothSettings();
                    }
                }).create();

        try {
            PackageManager packageManager = this.getPackageManager();
            PackageInfo info = packageManager.getPackageInfo(this.getPackageName(), 0);
            mVersionName = info.versionName;
            Log.i(TAG, this.getClass().getSimpleName() + " Spine server Test Application Version " + mVersionName);
        } catch (NameNotFoundException e) {
            Log.e(TAG, this.getClass().getSimpleName() + e.toString());
        }
    }

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

        if (deviceListAdapter != null) {
            deviceListAdapter.reloadItems();
        }
        switch (requestCode) {
        case BLUETOOTH_SETTINGS:
            break;
        }
    }

    private void startBluetoothSettings() {
        this.startActivityForResult(new Intent(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS),
                BLUETOOTH_SETTINGS);
    }

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

        if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
            this.bluetoothDisabledDialog.show();
        }
        if (deviceListAdapter != null) {
            deviceListAdapter.reloadItems();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mSpineManager.removeListener(this);
        this.unregisterReceiver(this.mCommandReceiver);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.bluetoothSettingsButton:
            this.startBluetoothSettings();
            break;
        }
    }

    private class GeneralReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (deviceListAdapter != null)
                deviceListAdapter.reloadItems();
        }
    }

    /**
     * Adapter class for sensor list
     * @author scott.coleman
     *
     */
    private class ManagerItemAdapter extends ArrayAdapter<BioSensor> implements OnCheckedChangeListener {
        private int layoutId;
        private LayoutInflater layoutInflater;
        private HashMap<View, String> viewDeviceMap = new HashMap<View, String>();

        public ManagerItemAdapter(Context context, int textViewResourceId) {
            super(context, textViewResourceId, new ArrayList<BioSensor>());

            this.layoutId = textViewResourceId;
            layoutInflater = (LayoutInflater) this.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);

            this.setNotifyOnChange(false);

            this.reloadItems();
        }

        public void reloadItems() {
            this.reloadItems(true);
        }

        private void reloadItems(boolean notify) {
            this.clear();

            for (BioSensor bioSensor : mBioSensors) {
                this.add(bioSensor);
            }

            if (notify) {
                this.notifyDataSetChanged();
            }
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            BioSensor bioSensor = this.getItem(position);
            View v = layoutInflater.inflate(this.layoutId, null);

            if (bioSensor == null) {
                return v;
            }

            String statusString = Util.connectionStatusToString(bioSensor.mConnectionStatus);

            ((TextView) v.findViewById(R.id.text1)).setText(bioSensor.mBTName);
            ((TextView) v.findViewById(R.id.status)).setText(statusString);

            ((ToggleButton) v.findViewById(R.id.enabled)).setChecked(bioSensor.mEnabled);
            ((ToggleButton) v.findViewById(R.id.enabled)).setOnCheckedChangeListener(this);
            ((ToggleButton) v.findViewById(R.id.enabled)).setTag(bioSensor.mBTAddress);

            String param = SharedPref.getParamForDevice(mInstance, bioSensor.mBTAddress);

            if (param != null) {
                ((Button) v.findViewById(R.id.parameter)).getBackground().setColorFilter(Color.GREEN,
                        PorterDuff.Mode.MULTIPLY);
                ((Button) v.findViewById(R.id.parameter)).setText(param);
            } else {
                ((Button) v.findViewById(R.id.parameter)).getBackground().setColorFilter(Color.LTGRAY,
                        PorterDuff.Mode.MULTIPLY);
                ((Button) v.findViewById(R.id.parameter)).setText("Parameter");

            }

            ((Button) v.findViewById(R.id.parameter)).setTag(bioSensor.mBTAddress);

            viewDeviceMap.put(v, bioSensor.mBTAddress);

            return v;
        }

        @Override
        public void onCheckedChanged(final CompoundButton buttonView, boolean isChecked) {

            if (buttonView.getId() == R.id.enabled) {
                String address = (String) buttonView.getTag();
                SpineServiceCommand serviceCommand = null;

                serviceCommand = new SpineServiceCommand();
                serviceCommand.setBtAddress(address);

                if (isChecked) {
                    serviceCommand.setCommand(SpineServiceCommand.COMMAND_ENABLED);
                    // We technically don't have do to this because we'll receive a STATUS_PAIRED_DEVICES
                    // command from the service as a result of the service commena we send
                    // but we do it so the button updates immediately
                    // as opposed to waiting for a round trip to/from the service
                    updateBioSensorEnabled(address, true);
                } else {
                    serviceCommand.setCommand(SpineServiceCommand.COMMAND_DISABLED);
                    updateBioSensorEnabled(address, false);
                }

                // We need to tell the service to enable or disable this sensor
                mSpineManager.serviceCommand(serviceCommand);
                this.reloadItems();
            } else if (buttonView.getId() == R.id.parameter) {
            }

        }
    }

    @Override
    public void newNodeDiscovered(Node newNode) {
    }

    @Override
    public void received(ServiceMessage msg) {
    }

    @Override
    public void received(Data data) {
    }

    @Override
    public void discoveryCompleted(Vector activeNodes) {
    }

    @Override
    public void onStatusReceived(BioFeedbackStatus bfs) {
        Log.d(TAG, this.getClass().getSimpleName() + ".onStatusReceived(" + bfs.messageId + ")");

        String name = bfs.name;
        if (name == null)
            name = "sensor node";
        if (bfs.messageId.equals("CONN_CONNECTING")) {
            Log.i(TAG, this.getClass().getSimpleName() + " Received command : " + bfs.messageId + " to " + name);
            updateBioSensorConnectionStatus(name, BioSensor.CONN_CONNECTING);
        } else if (bfs.messageId.equals("CONN_ANY_CONNECTED")) {
            Log.i(TAG, this.getClass().getSimpleName() + " Received command : " + bfs.messageId + " to " + name);
            updateBioSensorConnectionStatus(name, BioSensor.CONN_CONNECTED);

        } else if (bfs.messageId.equals("CONN_CONNECTION_LOST")) {
            Log.i(TAG, this.getClass().getSimpleName() + " Received command : " + bfs.messageId + " to " + name);
            updateBioSensorConnectionStatus(name, BioSensor.CONN_PAIRED);

        } else if (bfs.messageId.equals("STATUS_PAIRED_DEVICES")) {
            // bfs.address contains a json arrary containing status of all BT Devices
            Log.i(TAG, this.getClass().getSimpleName() + " Received command : " + bfs.messageId + " to " + name);

            Log.i(TAG, this.getClass().getSimpleName() + bfs.address);
            // Populate the mSensors array with a list of all paired sensors
            populateBioSensors(bfs.address);
        }

        if (deviceListAdapter != null)
            deviceListAdapter.reloadItems();
    }

    /**
     * Receives a json string containing data about all of the paired sensors
     * the adds a new BioSensor for each one to the mBioSensors collection
     * 
     * @param jsonString String containing info on all paired devices
     */
    private void populateBioSensors(String jsonString) {

        Log.d(TAG, this.getClass().getSimpleName() + " populateBioSensors");

        // Now clear it out and Re-populate it.
        mBioSensors.clear();
        try {
            JSONArray jsonArray = new JSONArray(jsonString);
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                Boolean enabled = jsonObject.getBoolean("enabled");
                String name = jsonObject.getString("name");
                String address = jsonObject.getString("address");
                int connectionStatus = jsonObject.getInt("connectionStatus");

                if (name.equalsIgnoreCase("system")) {
                    mBluetoothEnabled = enabled;
                } else {
                    Log.i(TAG, "Adding sensor " + name + ", " + address + (enabled ? ", enabled" : ", disabled")
                            + " : " + Util.connectionStatusToString(connectionStatus));
                    Log.i(TAG, this.getClass().getSimpleName() + " Adding sensor " + name + ", " + address
                            + (enabled ? ", enabled" : ", disabled"));
                    BioSensor bioSensor = new BioSensor(name, address, enabled);

                    bioSensor.mConnectionStatus = connectionStatus;
                    mBioSensors.add(bioSensor);
                }
            }
        } catch (JSONException e) {
            Log.e(TAG, e.toString());
        }
    }

    void updateBioSensorConnectionStatus(String name, int status) {
        for (BioSensor bioSensor : mBioSensors) {
            if (bioSensor.mBTName.equalsIgnoreCase(name)) {
                bioSensor.mConnectionStatus = status;
            }
        }
    }

    void updateBioSensorEnabled(String address, Boolean enabled) {
        for (BioSensor bioSensor : mBioSensors) {
            if (bioSensor.mBTAddress.equalsIgnoreCase(address)) {
                bioSensor.mEnabled = enabled;
            }
        }
    }

}