com.zentri.zentri_ble_command_demo.DeviceInfoActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.zentri.zentri_ble_command_demo.DeviceInfoActivity.java

Source

/*
 * Copyright (C) 2015, Zentri, Inc. All Rights Reserved.
 *
 * The Zentri BLE Android Libraries and Zentri BLE example applications are provided free of charge
 * by Zentri. The combined source code, and all derivatives, are licensed by Zentri SOLELY for use
 * with devices manufactured by Zentri, or devices approved by Zentri.
 *
 * Use of this software on any other devices or hardware platforms is strictly prohibited.
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.zentri.zentri_ble_command_demo;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

import com.zentri.zentri_ble_command.Command;
import com.zentri.zentri_ble_command.CommandMode;
import com.zentri.zentri_ble_command.ErrorCode;
import com.zentri.zentri_ble_command.GPIODirection;
import com.zentri.zentri_ble_command.GPIOFunction;
import com.zentri.zentri_ble_command.ZentriOSBLEManager;
import com.zentri.zentri_ble_command.Result;

public class DeviceInfoActivity extends AppCompatActivity {
    public static final String TAG = "DeviceInfo";

    private final long DISCONNECT_TIMEOUT_MS = 10000;

    private static final int ADC_GPIO = 12;//thermistor on wahoo
    private static final int TEST_GPIO = 9;//button2 on wahoo
    private static final int LED_GPIO = 14;

    private TextView mADCTextView;
    private TextView mGPIOTextView;
    private Button mUpdateButton;
    private ToggleButton mLedButton;
    private int mLedState = 0;

    private ToggleButton mModeButton;
    private int mCurrentMode;

    private Button mSendTextButton;
    private EditText mTextToSendBox;

    private TextView mReceivedDataTextBox;

    private ServiceConnection mConnection;
    private ZentriOSBLEService mService;
    private boolean mBound = false;

    private LocalBroadcastManager mLocalBroadcastManager;
    private BroadcastReceiver mBroadcastReceiver;
    private IntentFilter mReceiverIntentFilter;

    private ZentriOSBLEManager mZentriOSBLEManager;

    private Dialog mDisconnectDialog;

    private boolean mADCUpdateInProgress = false;
    private boolean mGPIOUpdateInProgress = false;
    private int mADCUpdateID, mGPIOUpdateID;

    private boolean mDisconnecting = false;

    private Handler mHandler;
    private Runnable mDisconnectTimeoutTask;

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

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        toolbar.setTitle(R.string.title_activity_device_info);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        mADCTextView = (TextView) findViewById(R.id.adc_value);
        mGPIOTextView = (TextView) findViewById(R.id.gpio_value);
        mLedButton = (ToggleButton) findViewById(R.id.led_button);

        mLedButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mLedButton.isChecked()) {
                    mLedState = 1;
                    writeLedState();
                } else {
                    mLedState = 0;
                    writeLedState();
                }
            }
        });

        mUpdateButton = (Button) findViewById(R.id.update_button);
        mUpdateButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                updateValues();
            }
        });

        mModeButton = (ToggleButton) findViewById(R.id.modeButton);
        mModeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mModeButton.isChecked()) {
                    mCurrentMode = ZentriOSBLEManager.MODE_STREAM;
                } else {
                    mCurrentMode = ZentriOSBLEManager.MODE_COMMAND_REMOTE;
                }
                mZentriOSBLEManager.setMode(mCurrentMode);
            }
        });

        mTextToSendBox = (EditText) findViewById(R.id.textToSend);
        mSendTextButton = (Button) findViewById(R.id.sendTextButton);
        mSendTextButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String data = mTextToSendBox.getText().toString();
                if (data != null && !data.isEmpty()) {
                    mZentriOSBLEManager.writeData(data);
                }

                mTextToSendBox.setText("");//clear input after send
            }
        });

        mReceivedDataTextBox = (TextView) findViewById(R.id.receivedDataBox);

        initBroadcastManager();
        initBroadcastReceiver();
        initServiceConnection();
        initReceiverIntentFilter();

        GUISetCommandMode();//set up gui for command mode initially

        mHandler = new Handler();

        mDisconnectTimeoutTask = new Runnable() {
            @Override
            public void run() {
                dismissProgressDialog();
                showErrorDialog(R.string.error, R.string.discon_timeout_message);
            }
        };
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_device_info, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
        case R.id.action_about:
            openAboutDialog();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onBackPressed() {
        disconnect();
    }

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

        mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, mReceiverIntentFilter);

        Intent serviceIntent = new Intent(getApplicationContext(), ZentriOSBLEService.class);
        bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
    }

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

        //quickly disconnect to make sure we are definitely disconnected
        mZentriOSBLEManager.disconnect(!ZentriOSBLEService.DISABLE_TX_NOTIFY);

        mLocalBroadcastManager.unregisterReceiver(mBroadcastReceiver);

        if (mBound) {
            unbindService(mConnection);
        }
    }

    private void initServiceConnection() {
        mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName className, IBinder service) {
                ZentriOSBLEService.LocalBinder binder = (ZentriOSBLEService.LocalBinder) service;
                mService = binder.getService();
                mBound = true;

                mZentriOSBLEManager = mService.getManager();
                mZentriOSBLEManager.setMode(ZentriOSBLEManager.MODE_COMMAND_REMOTE);
                mZentriOSBLEManager.setSystemCommandMode(CommandMode.MACHINE);
                initGPIOs();
                updateValues();
            }

            @Override
            public void onServiceDisconnected(ComponentName arg0) {
                mBound = false;
            }
        };
    }

    private void initBroadcastReceiver() {
        mBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                // Get extra data included in the Intent
                String action = intent.getAction();

                switch (action) {
                case ZentriOSBLEService.ACTION_COMMAND_SENT:
                    String command = ZentriOSBLEService.getCommand(intent).toString();
                    Log.d(TAG, "Command " + command + " sent");
                    break;

                case ZentriOSBLEService.ACTION_COMMAND_RESULT:
                    handleCommandResponse(intent);
                    break;

                case ZentriOSBLEService.ACTION_MODE_WRITE:
                    int mode = ZentriOSBLEService.getMode(intent);
                    if (mode == ZentriOSBLEManager.MODE_STREAM) {
                        //disable buttons while in stream mode (must be in rem command to work)
                        GUISetStreamMode();
                    } else {
                        GUISetCommandMode();
                    }
                    break;

                case ZentriOSBLEService.ACTION_STRING_DATA_READ:
                    if (mCurrentMode == ZentriOSBLEManager.MODE_STREAM) {
                        String text = ZentriOSBLEService.getData(intent);
                        updateReceivedTextBox(text);
                    }
                    break;

                case ZentriOSBLEService.ACTION_ERROR:
                    ErrorCode errorCode = ZentriOSBLEService.getErrorCode(intent);
                    //handle errors
                    switch (errorCode) {
                    case DEVICE_ERROR:
                        //connection state change without request
                        if (mDisconnecting) {
                            mDisconnecting = false;
                            dismissProgressDialog();
                            showErrorDialog(R.string.error, R.string.device_error_message);
                        }
                        break;

                    case DISCONNECT_FAILED:
                        mDisconnecting = false;
                        dismissProgressDialog();
                        showDisconnectErrorDialog(R.string.error, R.string.discon_err_message);
                        break;

                    }
                    break;

                case ZentriOSBLEService.ACTION_DISCONNECTED:
                    mHandler.removeCallbacks(mDisconnectTimeoutTask);//cancel timeout
                    dismissProgressDialog();
                    finish();
                    break;
                }
            }
        };
    }

    public void initBroadcastManager() {
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(DeviceInfoActivity.this);
    }

    public void initReceiverIntentFilter() {
        mReceiverIntentFilter = new IntentFilter();
        mReceiverIntentFilter.addAction(ZentriOSBLEService.ACTION_DISCONNECTED);
        mReceiverIntentFilter.addAction(ZentriOSBLEService.ACTION_COMMAND_RESULT);
        mReceiverIntentFilter.addAction(ZentriOSBLEService.ACTION_ERROR);
        mReceiverIntentFilter.addAction(ZentriOSBLEService.ACTION_STRING_DATA_READ);
        mReceiverIntentFilter.addAction(ZentriOSBLEService.ACTION_MODE_WRITE);
    }

    private void initGPIOs() {
        mZentriOSBLEManager.GPIOFunctionSet(ADC_GPIO, GPIOFunction.NONE);
        mZentriOSBLEManager.GPIOFunctionSet(TEST_GPIO, GPIOFunction.NONE);
        mZentriOSBLEManager.GPIOFunctionSet(LED_GPIO, GPIOFunction.NONE);

        mZentriOSBLEManager.GPIOFunctionSet(TEST_GPIO, GPIOFunction.STDIO);
        mZentriOSBLEManager.GPIOFunctionSet(LED_GPIO, GPIOFunction.STDIO);

        mZentriOSBLEManager.GPIODirectionSet(TEST_GPIO, GPIODirection.INPUT);
        mZentriOSBLEManager.GPIODirectionSet(LED_GPIO, GPIODirection.OUTPUT_LOW);
    }

    private void updateValues() {
        if (!mADCUpdateInProgress && !mGPIOUpdateInProgress) {
            mADCUpdateInProgress = true;
            mGPIOUpdateInProgress = true;

            Log.d(TAG, "Updating values");
            mADCUpdateID = mZentriOSBLEManager.adc(ADC_GPIO);
            mGPIOUpdateID = mZentriOSBLEManager.GPIOGet(TEST_GPIO);
        } else {
            showToast("Update in progress...", Toast.LENGTH_SHORT);
        }
    }

    private void handleCommandResponse(Intent intent) {
        Command command = ZentriOSBLEService.getCommand(intent);
        int code = ZentriOSBLEService.getResponseCode(intent);
        int id = ZentriOSBLEService.getCommandID(intent);

        String result = ZentriOSBLEService.getData(intent);
        String message = "";

        Log.d(TAG, "Command " + command + " result");

        if (id == mADCUpdateID) {
            mADCUpdateInProgress = false;

            if (code == Result.SUCCESS) {
                message = String.format("ADC: %s", result);
                mADCTextView.setText(message);
            } else {
                showToast("ERROR - failed to update ADC", Toast.LENGTH_SHORT);
            }
        } else if (id == mGPIOUpdateID) {
            mGPIOUpdateInProgress = false;

            if (code == Result.SUCCESS) {
                message = String.format("GPIO: %s", result);
                mGPIOTextView.setText(message);
            } else {
                showToast("ERROR - failed to update GPIO", Toast.LENGTH_SHORT);
            }
        }
    }

    //set up gui elements for command mode operation
    private void GUISetCommandMode() {
        mLedButton.setEnabled(true);
        mUpdateButton.setEnabled(true);
        mSendTextButton.setEnabled(false);
        mTextToSendBox.setVisibility(View.INVISIBLE);
    }

    //set up gui elements for command mode operation
    private void GUISetStreamMode() {
        mLedButton.setEnabled(false);
        mUpdateButton.setEnabled(false);
        mSendTextButton.setEnabled(true);
        mTextToSendBox.setVisibility(View.VISIBLE);
    }

    private void disconnect() {
        mDisconnecting = true;
        showDisconnectDialog();
        mZentriOSBLEManager.disconnect(ZentriOSBLEService.DISABLE_TX_NOTIFY);
        mHandler.postDelayed(mDisconnectTimeoutTask, DISCONNECT_TIMEOUT_MS);
    }

    private void updateReceivedTextBox(String newData) {
        mReceivedDataTextBox.append(newData);
    }

    private void clearReceivedTextBox() {
        mReceivedDataTextBox.setText("");
    }

    private void showDisconnectDialog() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mDisconnectDialog = Util.showProgressDialog(DeviceInfoActivity.this,
                        R.string.disconnect_dialog_title, R.string.disconnect_dialog_message);
            }
        });
    }

    private void showDisconnectErrorDialog(final int titleID, final int msgID) {
        AlertDialog.Builder builder = new AlertDialog.Builder(DeviceInfoActivity.this);

        builder.setTitle(titleID).setMessage(msgID)
                .setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        disconnect();
                    }
                }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        DeviceInfoActivity.this.finish();
                    }
                }).create().show();
    }

    private void showErrorDialog(final int titleID, final int msgID) {
        AlertDialog.Builder builder = new AlertDialog.Builder(DeviceInfoActivity.this);

        builder.setTitle(titleID).setMessage(msgID)
                .setNegativeButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        DeviceInfoActivity.this.finish();
                    }
                }).create().show();
    }

    private void showToast(final String msg, final int duration) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), msg, duration).show();
            }
        });
    }

    private void dismissProgressDialog() {
        if (mDisconnectDialog != null) {
            mDisconnectDialog.dismiss();
        }
    }

    private void writeLedState() {
        mZentriOSBLEManager.GPIOSet(LED_GPIO, mLedState);
    }

    private void openAboutDialog() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Util.makeAboutDialog(DeviceInfoActivity.this);
            }
        });
    }
}