com.pipirssolutions.aeseztargetcontroller.ProgramFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.pipirssolutions.aeseztargetcontroller.ProgramFragment.java

Source

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.pipirssolutions.aeseztargetcontroller;

import android.app.ActionBar;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;

/**
 * This fragment controls Bluetooth to communicate with other devices.
 */
public class ProgramFragment extends Fragment {

    // Intent request codes
    private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
    private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
    private static final int REQUEST_ENABLE_BT = 3;

    // Layout Views
    private TextView mProgramNameView;
    private TextView mProgramModeView;
    private TextView mProgramModeTimeView;
    private TextView mProgramTotalTimeView;
    private Button mSendTransmissionButton;

    private final static String TAG = "ProgramFragment";

    /**
     * Name of the connected device
     */
    private String mConnectedDeviceName = null;

    /**
     * Program Structure containing program variables
     */
    private ArrayList<Program> mPrograms;

    //current program running
    private String currentProgramName = "Select an program";
    private ArrayList<String> mProgram;

    /**
     * String buffer for outgoing transmission
     */
    private StringBuffer mOutStringBuffer;

    /**
     * Local Bluetooth adapter
     */
    private BluetoothAdapter mBluetoothAdapter = null;

    /**
     * Member object for the bluetooth communication services
     */
    private BluetoothCommunicationService mCommunicationService = null;
    private byte[] payLoad;
    private boolean buttonEnabled;

    /**
     * Heartbeat timer
     */
    private Handler handler;
    private int ms;
    private boolean blocked;

    /**
     * @param programTitle
     * @param programCode
     */

    //this call back method sets the program code and title etc from the activity
    public void setProgram(String programTitle, ArrayList<String> programCode) {

        this.mProgram = programCode;
        this.currentProgramName = programTitle;
        this.mProgramNameView.setText(programTitle);

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);

        handler = new Handler();

        blocked = true;

        // Get local Bluetooth adapter
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        // If the adapter is null, then Bluetooth is not supported
        if (mBluetoothAdapter == null) {
            FragmentActivity activity = getActivity();
            Toast.makeText(activity, "Bluetooth is not available", Toast.LENGTH_LONG).show();
            activity.finish();
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        // If BT is not on, request that it be enabled.
        // setupChat() will then be called during onActivityResult
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
            // Otherwise, setup the chat session
        } else if (mCommunicationService == null) {
            setupTransmission();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mCommunicationService != null) {
            mCommunicationService.stop();
        }
    }

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

        // Performing this check in onResume() covers the case in which BT was
        // not enabled during onStart(), so we were paused to enable it...
        // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
        if (mCommunicationService != null) {
            // Only if the state is STATE_NONE, do we know that we haven't started already
            if (mCommunicationService.getState() == BluetoothCommunicationService.STATE_NONE) {
                // Start the Bluetooth chat services
                mCommunicationService.start();
            }
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_bluetooth_program, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        mProgramNameView = (TextView) view.findViewById(R.id.program_name);
        mProgramModeView = (TextView) view.findViewById(R.id.program_mode);
        mProgramModeTimeView = (TextView) view.findViewById(R.id.program_mode_time);
        mProgramTotalTimeView = (TextView) view.findViewById(R.id.program_totaltime);
        mSendTransmissionButton = (Button) view.findViewById(R.id.button_send);
    }

    /**
     * Set up the UI and background operations for chat.
     */
    private void setupTransmission() {

        // Initialize the send button with a listener that for click events
        mSendTransmissionButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // Send a message using content of the edit text widget
                View view = getView();
                if (null != view) {

                    buttonEnabled = true;

                    //TODO remove the code below
                    sendCode(mProgram);
                }
            }
        });

        // Initialize the BluetoothChatService to perform bluetooth connections
        mCommunicationService = new BluetoothCommunicationService(getActivity(), mHandler);
        // Initialize the buffer for outgoing messages
        mOutStringBuffer = new StringBuffer("");
    }

    /**
     * Makes this device discoverable.
     */
    private void ensureDiscoverable() {
        if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            startActivity(discoverableIntent);
        }
    }

    /**
     * Sends a message.
     *
     * @param programCode A ArrayList<string> of code to send.
     */
    private void sendCode(ArrayList<String> programCode) {
        // Check that we're actually connected before trying anything
        if (mCommunicationService.getState() != BluetoothCommunicationService.STATE_CONNECTED) {
            Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }
        // Check that there's actually something to send
        if (programCode.size() > 0) {

            //send start of code
            String temp = "Start of Transmission -program name: " + currentProgramName + " \n \r";
            byte[] send = temp.getBytes();
            mCommunicationService.write(send);

            // loop through the array and send string by string
            for (int i = 0; i < programCode.size(); i++) {

                // Get the message bytes and tell the BluetoothChatService to write
                send = programCode.get(i).getBytes();
                mCommunicationService.write(send);

                // Reset out string buffer to zero and clear the edit text field
                mOutStringBuffer.setLength(0);
                //FIXME check this out
                //mTransmissionEditText.setText(mOutStringBuffer);

            }

            //send end of code
            temp = "End of transmission \n \r";
            send = temp.getBytes();
            mCommunicationService.write(send);

        }
    }

    /**
     * Sends a message.
     *
     * @param message A message of string to send.
     */
    private void sendMessage(String message) {
        // Check that we're actually connected before trying anything
        if (mCommunicationService.getState() != BluetoothCommunicationService.STATE_CONNECTED) {
            Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }
        // Check that there's actually something to send
        if (message.length() > 0) {

            // Get the message bytes and tell the BluetoothChatService to write
            byte[] send = message.getBytes();
            mCommunicationService.write(send);
            // Reset out string buffer to zero and clear the edit text field
            mOutStringBuffer.setLength(0);

        }

    }

    /**
     * @param c a command to send
     */
    private void sendCommand(char c) {
        // Check that we're actually connected before trying anything
        if (mCommunicationService.getState() != BluetoothCommunicationService.STATE_CONNECTED) {
            Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }
        // Get the message bytes and tell the BluetoothChatService to write
        byte[] send = { (byte) 2, (byte) 0, (byte) 7, (byte) c, (byte) 0, (byte) 0, (byte) 3 };
        mCommunicationService.write(send);
        // Reset out string buffer to zero and clear the edit text field
        mOutStringBuffer.setLength(0);

    }

    /**
     * @param c a command to send
     */
    private void sendACK(char c) {
        // Check that we're actually connected before trying anything
        if (mCommunicationService.getState() != BluetoothCommunicationService.STATE_CONNECTED) {
            Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }
        String temp = "Ack";
        // Get the message bytes and tell the BluetoothChatService to write
        byte[] send = temp.getBytes();
        mCommunicationService.write(send);
        // Reset out string buffer to zero and clear the edit text field
        mOutStringBuffer.setLength(0);

    }

    /**
     * The action listener for the EditText widget, to listen for the return key
     */
    private TextView.OnEditorActionListener mWriteListener = new TextView.OnEditorActionListener() {
        public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
            // If the action is a key-up event on the return key, send the message
            if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {
                String message = view.getText().toString();
                sendMessage(message);
            }
            return true;
        }
    };

    /**
     * Updates the status on the action bar.
     *
     * @param resId a string resource ID
     */
    private void setStatus(int resId) {
        FragmentActivity activity = getActivity();
        if (null == activity) {
            return;
        }
        final ActionBar actionBar = activity.getActionBar();
        if (null == actionBar) {
            return;
        }
        actionBar.setSubtitle(resId);
    }

    /**
     * Updates the status on the action bar.
     *
     * @param subTitle status
     */
    private void setStatus(CharSequence subTitle) {
        FragmentActivity activity = getActivity();
        if (null == activity) {
            return;
        }
        final ActionBar actionBar = activity.getActionBar();
        if (null == actionBar) {
            return;
        }
        actionBar.setSubtitle(subTitle);
    }

    /**
     * The Handler that gets information back from the BluetoothCommunicationService
     */
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            FragmentActivity activity = getActivity();
            switch (msg.what) {
            case Constants.MESSAGE_STATE_CHANGE:
                switch (msg.arg1) {
                case BluetoothCommunicationService.STATE_CONNECTED:
                    setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
                    break;
                case BluetoothCommunicationService.STATE_CONNECTING:
                    setStatus(R.string.title_connecting);
                    break;
                case BluetoothCommunicationService.STATE_LISTEN:
                case BluetoothCommunicationService.STATE_NONE:
                    setStatus(R.string.title_not_connected);
                    break;
                }

                break;
            case Constants.MESSAGE_WRITE:
                byte[] writeBuf = (byte[]) msg.obj;

                // construct a string from the buffer
                String writeMessage = new String(writeBuf);

                //Toast.makeText(activity, "Incomming msg: " + writeMessage, Toast.LENGTH_SHORT).show();

                break;

            case Constants.MESSAGE_READ:

                byte[] readBuf = (byte[]) msg.obj;

                // construct a string from the valid bytes in the buffer
                String readMessage = new String(readBuf, 0, msg.arg1);

                processData(readBuf, activity);

                break;

            case Constants.MESSAGE_DEVICE_NAME:
                // save the connected device's name
                mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
                if (null != activity) {
                    Toast.makeText(activity, "Connected to " + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
                }
                break;
            case Constants.MESSAGE_TOAST:
                if (null != activity) {
                    Toast.makeText(activity, msg.getData().getString(Constants.TOAST), Toast.LENGTH_SHORT).show();
                }
                break;
            }
        }
    };

    /**
     * Invariant
     *
     * @param readBuf
     * @param activity
     */
    private void processData(byte[] readBuf, FragmentActivity activity) {

        final StringBuilder builder = new StringBuilder();
        int FRAMELENGTH = 0;

        //builder.append(String.format("%02x", readBuf[0])).toString()
        switch (((int) readBuf[0])) {

        //Fetch STX = this is an start of transmission
        case 02:

            Log.d(TAG, String.format("STX found "));

            //Calculate FRAMELENGTH & check that its not corrupt
            FRAMELENGTH = readBuf[1] * 256;
            FRAMELENGTH = FRAMELENGTH + readBuf[2];

            Log.d(TAG, String.format("Framelength = " + FRAMELENGTH));

            if (FRAMELENGTH < 7) {

                Log.d(TAG, String.format("Corrupt framelength <7 = " + FRAMELENGTH));

                //NACK
                sendCommand((char) 21);

                break;
            }

            //Fetch etx this is the end of the transmission
            if (((int) readBuf[FRAMELENGTH - 1]) != 3) {

                Log.d(TAG, String.format("No etx found"));

                //NACK
                sendCommand((char) 21);

                break;
            }

            Log.d(TAG, String.format("Etx was found"));

            //update Payload
            payLoad = new byte[FRAMELENGTH - 6];
            for (int i = 4; i < FRAMELENGTH - 2; i++) {
                payLoad[i - 4] = readBuf[i];

            }

            //check  checksum
            int cs = readBuf[1] ^ readBuf[2];
            cs = cs ^ readBuf[3];

            for (int i = 0; i < payLoad.length; i++) {
                cs = cs ^ payLoad[i];
            }

            if (cs != readBuf[FRAMELENGTH - 1]) {

                Log.d(TAG, String.format("CS was not correct"));
                //TODO return NACK here and BREAK
            }

            //Fetch the command ()
            switch (builder.append(String.format("%02x", readBuf[3])).toString()) {

            case "81":

                //HeartBeat
                Log.d(TAG, String.format("Heatbeat Recieved "));

                //blocked initiate timer
                if (!blocked) {

                    //resetted ms counter
                    ms = 0;
                    Log.d(TAG, String.format("Timer was resseted "));

                }
                //reset timer normal
                else {
                    blocked = false;
                    ms = 0;
                    mHandler.postDelayed(heartBeatTimer, 100);
                    Log.d(TAG, String.format("Timer was unblocked and reinitialised "));
                }

                //ACK
                sendCommand((char) 6);
                break;

            case "82":
                //Display

                Log.d(TAG, String.format("Display Command Recieved "));
                mProgramModeView.setText(new String(payLoad));
                //ACK
                sendACK((char) 6);
                Thread thread = new Thread();
                try {
                    thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                sendACK((char) 6);
                try {
                    thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                sendCommand((char) 6);

                break;

            case "83":
                //repeat
                Log.d(TAG, String.format("Repeat Command Recieved "));

                //ACK
                sendCommand((char) 6);
                break;

            case "84":
                //Time
                Log.d(TAG, String.format("Time Command Recieved "));
                mProgramModeTimeView.setText(new String(payLoad));

                //ACK
                sendCommand((char) 6);

                break;

            case "85":

                //requesting the state of the button if the button is enabled start!

                if (buttonEnabled) {
                    sendCommand((char) 0);
                    Log.d(TAG, String.format("Button status was requested: " + buttonEnabled));
                    buttonEnabled = false;
                    Log.d(TAG, String.format("Button status has changed:" + buttonEnabled));

                } else {
                    sendCommand((char) 1);

                    //send the state of the button.
                    Log.d(TAG, String.format("Button status was requested: " + buttonEnabled));
                }

                break;

            case "86":
                //Changeprogram_req
                Log.d(TAG, String.format("Request program command recieved "));
                if (mProgram != null)
                    sendCode(mProgram);

                //TODO tell the user the button is enabled

                break;

            case "06":
                //ACK
                Log.d(TAG, String.format("Ack Command Recieved "));

                break;

            case "15":
                //NAK

                //reSend Program
                sendCode(mProgram);

                Log.d(TAG, String.format("NCK Command Recieved "));
                break;
            }

            break;

        }

    }

    private Runnable heartBeatTimer = new Runnable() {

        @Override
        public void run() {
            //do something

            ms++;

            if (ms >= 20) {

                //stop and clear variables
                buttonEnabled = false;
                blocked = true;

                Log.d(TAG, String.format("Heartbeat timer was not resetted and have expired"));

            } else {
                //reset
                mHandler.postDelayed(this, 100);
            }
        }
    };

    private void reply() {

    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
        case REQUEST_CONNECT_DEVICE_SECURE:
            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK) {
                connectDevice(data, true);
            }
            break;
        case REQUEST_CONNECT_DEVICE_INSECURE:
            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK) {
                connectDevice(data, false);
            }
            break;
        case REQUEST_ENABLE_BT:
            // When the request to enable Bluetooth returns
            if (resultCode == Activity.RESULT_OK) {
                // Bluetooth is now enabled, so set up a chat session
                setupTransmission();
            } else {
                // User did not enable Bluetooth or an error occurred

                Toast.makeText(getActivity(), R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
                getActivity().finish();
            }
        }
    }

    /**
     * Establish connection with other divice
     *
     * @param data   An {@link android.content.Intent} with {@link DeviceListActivity#EXTRA_DEVICE_ADDRESS} extra.
     * @param secure Socket Security type - Secure (true) , Insecure (false)
     */
    private void connectDevice(Intent data, boolean secure) {
        // Get the device MAC address
        String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
        // Get the BluetoothDevice object
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        // Attempt to connect to the device
        mCommunicationService.connect(device, secure);
    }

    /**
     * put this in menu
     */
    public void launchDeviceFinder() {

        // Launch the DeviceListActivity to see devices and do scan
        Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
        startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);

    }
    /*
                case R.id.insecure_connect_scan: {
        
                        case R.id.discoverable: {
            // Ensure this device is discoverable by others
            ensureDiscoverable();
            return true;
        
        
     */

}