package com.dahanis.utils.bluetoothprinter;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.widget.Toast;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/**
* Created By: Seal.Wu
* Date: 2015/4/2
* Time: 16:20
*/
class BlueToothService implements IBlueToothService {
private static final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private final static BlueToothService blueToothService = new BlueToothService();
private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private BlueToothController blueToothController = BlueToothController.getInstance();
private List<BluetoothDevice> boundBluetoothDevice = new LinkedList<BluetoothDevice>();
private List<BluetoothDevice> unBoundBluetoothDevice = new LinkedList<BluetoothDevice>();
private BluetoothDevice currentBlueDevice;
private DeviceReceiver deviceReceiver;
private Context context;
private DataOutputStream os;
private DataInputStream is;
private BluetoothSocket bluetoothSocket;
private BluetoothServerSocket bluetoothServerSocket;
private boolean isConnected;
private ReadThread readThread;
public static BlueToothService getBlueToothService() {
return blueToothService;
}
private BlueToothService() {
}
public boolean isConnected() {
return isConnected;
}
private void registerBroadCastReceiver(Context context) {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
context.registerReceiver(broadcastReceiver, intentFilter);
}
@Override
public void getBluetoothDevice(Context context, DeviceReceiver deviceReceiver) {
this.context = context;
this.deviceReceiver = deviceReceiver;
registerBroadCastReceiver(context);
boundBluetoothDevice.clear();
unBoundBluetoothDevice.clear();
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
boundBluetoothDevice.addAll(pairedDevices);
deviceReceiver.boundDeviceReceive(boundBluetoothDevice);
deviceReceiver.unBoundDeviceReceive(unBoundBluetoothDevice);
deviceReceiver.onFinishedReceive();
}
public boolean checkBluetoothEnable() {
if (bluetoothAdapter == null) { // Device does not support Bluetooth
Toast.makeText(context, "您的设备不支持蓝牙功能!", Toast.LENGTH_SHORT).show();
return false;
} else {
if (!bluetoothAdapter.isEnabled()) {
bluetoothAdapter.enable();
long startTime = System.currentTimeMillis();
while (!bluetoothAdapter.isEnabled()) {
if (System.currentTimeMillis() - startTime > 10 * 1000) {
return false;
}
}
}
return true;
}
}
@Override
public void refreshDevices() {
boundBluetoothDevice.clear();
unBoundBluetoothDevice.clear();
makeSureBluetoothEnable();
blueToothController.searchDevices();
}
private void makeSureBluetoothEnable() {
if (!blueToothController.isOpen()) {
checkBluetoothEnable();
}
}
public void closeBluetooth() {
blueToothController.closeBluetooth();
}
@Override
public void connectDevice(BluetoothDevice bluetoothDevice, ConnectListener connectListener) throws IOException {
makeSureBluetoothEnable();
this.currentBlueDevice = bluetoothAdapter.getRemoteDevice(bluetoothDevice.getAddress());
if (bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
}
bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
try {
if (!bluetoothSocket.isConnected()) {
bluetoothSocket.connect();
}
isConnected = true;
} catch (IOException e) {
BluetoothLog.e(e);
new Thread() {
@Override
public void run() {
try {
bluetoothSocket.close();
if (bluetoothServerSocket != null) {
bluetoothServerSocket.close();
}
bluetoothServerSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord("printer", uuid);
bluetoothSocket = bluetoothServerSocket.accept();
} catch (IOException e1) {
BluetoothLog.e(e1);
}
super.run();
}
}.start();
throw e;
}
os = new DataOutputStream(bluetoothSocket.getOutputStream());
is = new DataInputStream(bluetoothSocket.getInputStream());
if (readThread != null) {
readThread.beak = true;
}
readThread = new ReadThread(is);
readThread.start();
if (connectListener != null) {
connectListener.onConnected(bluetoothSocket);
}
}
private final class ReadThread extends Thread {
private byte[] buffer = new byte[0x1000];
boolean beak;
private int rec = -1;
private DataInputStream is;
public ReadThread(DataInputStream inputStream) {
this.is = inputStream;
}
@Override
public void run() {
while (true) {
try {
int available = is.available();
if (available > 0) {
synchronized (this) {
rec = is.read(buffer, 0, available > buffer.length ? buffer.length
: available);
BluetoothLog.i("读取打印机状态完毕!");
}
}
} catch (IOException e) {
BluetoothLog.e(e);
}
try {
sleep(100);
} catch (InterruptedException e) {
BluetoothLog.e(e);
}
if (beak) {
break;
}
}
}
public byte[] getReadData() {
synchronized (this) {
return buffer;
}
}
public boolean getDataSucceed() {
return rec > 0;
}
public void clear() {
synchronized (this) {
buffer = new byte[0x1000];
}
rec = -1;
}
}
/**
* 断开连接并清空内部所有状态
*/
@Override
public void disConnectDevice() {
if (readThread != null) {
readThread.beak = true;
}
context.unregisterReceiver(broadcastReceiver);
if (bluetoothSocket != null) {
try {
if (os != null) os.close();
if (is != null) is.close();
bluetoothSocket.close();
} catch (IOException e) {
BluetoothLog.e(e);
}
}
if (bluetoothServerSocket != null) {
try {
bluetoothServerSocket.close();
} catch (IOException e) {
BluetoothLog.e(e);
}
}
isConnected = false;
boundBluetoothDevice.clear();
unBoundBluetoothDevice.clear();
}
public void writePic(byte[] data) throws IOException {
if (os != null) {
os.write(Cmd.ESCCmd.ESC_ALT);
os.flush();
}
int nBytesPerLine = 384 / 8 + 8;
int nLinesPerTest = 1;
nLinesPerTest = 30;
POS_Write_Pic_Data_Safety(data, 0, data.length, nLinesPerTest * nBytesPerLine);
}
public void writeData(byte[] data) throws IOException {
if (os != null) {
os.write(Cmd.ESCCmd.ESC_ALT);
os.flush();
}
int nBytesPerLine = data.length;
int nLinesPerTest = 1;
nLinesPerTest = 30;
POS_Write_Data_Safety(data, 0, data.length, nLinesPerTest * nBytesPerLine);
}
private synchronized int POS_Write_Pic_Data_Safety(byte[] buffer, int offset,
int count, int percount) throws IOException {
int idx = 0;
int curcount = 0;
byte[] reset = {0x1b, 0x40};
byte[] precbuf = new byte[1];
int timeout = 30 * 1000;
if (POS_QueryStatus(precbuf, timeout)) {
while (idx < count) {
if (count - idx > percount)
curcount = percount;
else
curcount = count - idx;
os.write(buffer, offset + idx, curcount);
os.flush();
if (!POS_QueryStatus(precbuf, timeout))
break;
else {
os.write(reset, 0, reset.length);
os.flush();
idx += curcount;
}
}
}
return idx;
}
private synchronized int POS_Write_Data_Safety(byte[] buffer, int offset,
int count, int percount) throws IOException {
int idx = 0;
int curcount = 0;
byte[] reset = {0x1b, 0x40};
byte[] precbuf = new byte[1];
int timeout = 30 * 1000;
if (POS_QueryStatus(precbuf, timeout)) {
while (idx < count) {
if (count - idx > percount)
curcount = percount;
else
curcount = count - idx;
os.write(buffer, offset + idx, curcount);
os.flush();
if (!POS_QueryStatus(precbuf, timeout))
break;
else {
os.write(reset, 0, reset.length);
os.flush();
idx += curcount;
}
}
}
return idx;
}
/**
* 使用1D 72 01这个命令,获取打印机状态。
*
* @param precbuf 长度为1的字节数组,存储返回的状态。
* @param timeout
* @return
*/
public boolean POS_QueryStatus(byte precbuf[], int timeout) throws IOException {
int retry;
byte pcmdbuf[] = {0x1D, 0x72, 0x01};
byte[] buffer = new byte[0x1000];
int rec = -1;
//byte pcmdbuf[] = { 0x10, 0x04, 0x01 };
retry = 3;
while (retry > 0) {
retry--;
readThread.clear();
os.write(pcmdbuf, 0, pcmdbuf.length);
os.flush();
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime < timeout) {
if (readThread.getDataSucceed()) {
return true;
}
}
}
return false;
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
BluetoothLog.i("Start search BlueToothDevices");
} else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
BluetoothLog.i("Search---founded BlueToothDevice: " + bluetoothDevice.getName() + " " + bluetoothDevice.getAddress());
for (BluetoothDevice bluetoothDevice1 : boundBluetoothDevice) {
if (bluetoothDevice1.getAddress().equals(bluetoothDevice.getAddress())) {
return;
}
}
for (BluetoothDevice bluetoothDevice1 : unBoundBluetoothDevice) {
if (bluetoothDevice1.getAddress().equals(bluetoothDevice.getAddress())) {
return;
}
}
if (bluetoothDevice.getBondState() == BluetoothDevice.BOND_BONDING) {
currentBlueDevice = bluetoothDevice;
boundBluetoothDevice.add(bluetoothDevice);
} else if (bluetoothDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
boundBluetoothDevice.add(bluetoothDevice);
} else if (bluetoothDevice.getBondState() == BluetoothDevice.BOND_NONE) {
unBoundBluetoothDevice.add(bluetoothDevice);
}
} else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
deviceReceiver.boundDeviceReceive(boundBluetoothDevice);
deviceReceiver.unBoundDeviceReceive(unBoundBluetoothDevice);
deviceReceiver.onFinishedReceive();
BluetoothLog.i("Finished Search BlueToothDevices");
}
}
};
}