iconsole-android/Application/src/main/java/org/surfsite/iconsole/BluetoothChatFragment.java
Harald Hoyer d2e60c858f ii
2017-04-27 08:21:38 +02:00

410 lines
15 KiB
Java

/*
* 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 org.surfsite.iconsole;
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.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.NumberPicker;
import android.widget.TextView;
import android.widget.Toast;
import org.surfsite.iconsole.R;
import org.surfsite.iconsole.common.logger.Log;
import java.util.Locale;
/**
* This fragment controls Bluetooth to communicate with other devices.
*/
public class BluetoothChatFragment extends Fragment {
private static final String TAG = "BluetoothChatFragment";
// 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 ListView mConversationView;
private Button mStartButton;
private Button mStopButton;
private Button mDisconnectButton;
private NumberPicker mLevel;
/**
* Name of the connected device
*/
private String mConnectedDeviceName = null;
/**
* Array adapter for the conversation thread
private ArrayAdapter<String> mConversationArrayAdapter;
*/
/**
* Local Bluetooth adapter
*/
private BluetoothAdapter mBluetoothAdapter = null;
/**
* Member object for the chat services
*/
private BluetoothChatService mChatService = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(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 (null == mBluetoothAdapter || !mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
// Otherwise, setup the chat session
} else if (mChatService == null) {
setupChat();
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mChatService != null) {
mChatService.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 (mChatService != null) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_bluetooth_chat, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
//mConversationView = (ListView) view.findViewById(R.id.in);
mStartButton = (Button) view.findViewById(R.id.button_start);
mStopButton = (Button) view.findViewById(R.id.button_stop);
mDisconnectButton = (Button) view.findViewById(R.id.button_disconnect);
mLevel = (NumberPicker) view.findViewById(R.id.Level);
mLevel.setMaxValue(16);
mLevel.setMinValue(1);
mLevel.setValue(5);
mLevel.setWrapSelectorWheel(false);
mLevel.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
}
/**
* Set up the UI and background operations for chat.
*/
private void setupChat() {
Log.d(TAG, "setupChat()");
/*
// Initialize the array adapter for the conversation thread
mConversationArrayAdapter = new ArrayAdapter<>(getActivity(), R.layout.message);
mConversationView.setAdapter(mConversationArrayAdapter);
*/
// Initialize the BluetoothChatService to perform bluetooth connections
mChatService = new BluetoothChatService(getActivity(), mHandler);
mStartButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mChatService.startIConsole();
}
});
mStopButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mChatService.stopIConsole();
}
});
mDisconnectButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mChatService.stop();
}
});
mStartButton.setEnabled(false);
mStopButton.setEnabled(false);
mDisconnectButton.setEnabled(false);
}
/**
* Makes this device discoverable for 300 seconds (5 minutes).
*/
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 message A string of text to send.
*/
private void sendMessage(String message) {
// Check that we're actually connected before trying anything
if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
mChatService.startIConsole();
}
/**
* 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 BluetoothChatService
*/
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 BluetoothChatService.STATE_CONNECTED:
setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
//mConversationArrayAdapter.clear();
mStartButton.setEnabled(true);
mStopButton.setEnabled(true);
mDisconnectButton.setEnabled(true);
break;
case BluetoothChatService.STATE_CONNECTING:
setStatus(R.string.title_connecting);
mStartButton.setEnabled(false);
mStopButton.setEnabled(false);
mDisconnectButton.setEnabled(false);
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
setStatus(R.string.title_not_connected);
mStartButton.setEnabled(false);
mStopButton.setEnabled(false);
mDisconnectButton.setEnabled(false);
break;
}
break;
case Constants.MESSAGE_DATA:
IConsole.Data data = (IConsole.Data) msg.obj;
// FIXME
// insert text here
/*
String dataMessage = String.format(Locale.US, "Time: %d Speed: %3.1f Power: %3.1f RPM: %d LVL: %d Dist: %4.1f Cal: %d HF: %d",
data.mTime, data.mSpeed10 / 10.0, data.mPower10 / 10.0, data.mRPM,
data.mLevel, data.mDistance10 / 10.0, data.mCalories, data.mHF);
*/
//mConversationArrayAdapter.add(mConnectedDeviceName + ": " + dataMessage);
break;
case Constants.MESSAGE_WRITE:
//byte[] writeBuf = (byte[]) msg.obj;
// construct a string from the buffer
//String writeMessage = new String(writeBuf);
//mConversationArrayAdapter.add("Me: " + writeMessage);
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);
//mConversationArrayAdapter.add(mConnectedDeviceName + ": " + readMessage);
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;
}
}
};
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
setupChat();
} else {
// User did not enable Bluetooth or an error occurred
Log.d(TAG, "BT not enabled");
Toast.makeText(getActivity(), R.string.bt_not_enabled_leaving,
Toast.LENGTH_SHORT).show();
getActivity().finish();
}
}
}
/**
* Establish connection with other device
*
* @param data An {@link 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
mChatService.connect(device);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.bluetooth_chat, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.secure_connect_scan: {
// Launch the DeviceListActivity to see devices and do scan
Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
return true;
}
case R.id.insecure_connect_scan: {
// Launch the DeviceListActivity to see devices and do scan
Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);
return true;
}
case R.id.discoverable: {
// Ensure this device is discoverable by others
ensureDiscoverable();
return true;
}
}
return false;
}
}