1 /*
2  * Copyright (C) 2014 Akexorcist
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package app.akexorcist.bluetotohspp.library;
18 
19 import java.util.ArrayList;
20 import java.util.Set;
21 
22 import android.annotation.SuppressLint;
23 import android.bluetooth.BluetoothAdapter;
24 import android.bluetooth.BluetoothDevice;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.os.Handler;
28 import android.os.Message;
29 import android.util.Log;
30 import android.widget.Toast;
31 
32 @SuppressLint("NewApi")
33 public class BluetoothSPP {
34     // Listener for Bluetooth Status & Connection
35     private BluetoothStateListener mBluetoothStateListener = null;
36     private OnDataReceivedListener mDataReceivedListener = null;
37     private BluetoothConnectionListener mBluetoothConnectionListener = null;
38     private AutoConnectionListener mAutoConnectionListener = null;
39 
40     // Context from activity which call this class
41     private Context mContext;
42 
43     // Local Bluetooth adapter
44     private BluetoothAdapter mBluetoothAdapter = null;
45 
46     // Member object for the chat services
47     private BluetoothService mChatService = null;
48 
49     // Name and Address of the connected device
50     private String mDeviceName = null;
51     private String mDeviceAddress = null;
52 
53     private boolean isAutoConnecting = false;
54     private boolean isAutoConnectionEnabled = false;
55     private boolean isConnected = false;
56     private boolean isConnecting = false;
57     private boolean isServiceRunning = false;
58 
59     private String keyword = "";
60     private boolean isAndroid = BluetoothState.DEVICE_ANDROID;
61     private String autoAddress = "";
62 
63     private BluetoothConnectionListener bcl;
64     private int c = 0;
65 
BluetoothSPP(Context context)66     public BluetoothSPP(Context context) {
67         Log.i("DEBUGGER_TAG", "BluetoothSPP ctor");
68 
69         mContext = context;
70         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
71     }
72 
73     public interface BluetoothStateListener {
onServiceStateChanged(int state)74         public void onServiceStateChanged(int state);
75     }
76 
77     public interface OnDataReceivedListener {
onDataReceived(byte[] data, String message)78         public void onDataReceived(byte[] data, String message);
79     }
80 
81     public interface BluetoothConnectionListener {
onDeviceConnected(String name, String address)82         public void onDeviceConnected(String name, String address);
onDeviceDisconnected()83         public void onDeviceDisconnected();
onDeviceConnectionFailed()84         public void onDeviceConnectionFailed();
85     }
86 
87     public interface AutoConnectionListener {
onAutoConnectionStarted()88         public void onAutoConnectionStarted();
onNewConnection(String name, String address)89         public void onNewConnection(String name, String address);
90     }
91 
isBluetoothAvailable()92     public boolean isBluetoothAvailable() {
93         try {
94             if (mBluetoothAdapter == null || mBluetoothAdapter.getAddress().equals(null))
95                 return false;
96         } catch (NullPointerException e) {
97              return false;
98         }
99         return true;
100     }
101 
isBluetoothEnabled()102     public boolean isBluetoothEnabled() {
103         return mBluetoothAdapter.isEnabled();
104     }
105 
isServiceAvailable()106     public boolean isServiceAvailable() {
107         return mChatService != null;
108     }
109 
isAutoConnecting()110     public boolean isAutoConnecting() {
111         return isAutoConnecting;
112     }
113 
startDiscovery()114     public boolean startDiscovery() {
115         return mBluetoothAdapter.startDiscovery();
116     }
117 
isDiscovery()118     public boolean isDiscovery() {
119         return mBluetoothAdapter.isDiscovering();
120     }
121 
cancelDiscovery()122     public boolean cancelDiscovery() {
123         return mBluetoothAdapter.cancelDiscovery();
124     }
125 
setupService()126     public void setupService() {
127         mChatService = new BluetoothService(mContext, mHandler);
128     }
129 
getBluetoothAdapter()130     public BluetoothAdapter getBluetoothAdapter() {
131         return mBluetoothAdapter;
132     }
133 
getServiceState()134     public int getServiceState() {
135         if(mChatService != null)
136             return mChatService.getState();
137         else
138             return -1;
139     }
140 
startService(boolean isAndroid)141     public void startService(boolean isAndroid) {
142         if (mChatService != null) {
143             if (mChatService.getState() == BluetoothState.STATE_NONE) {
144                 Log.i("DEBUGGER_TAG", "SPPstartService");
145                 isServiceRunning = true;
146                 mChatService.start(isAndroid);
147                 BluetoothSPP.this.isAndroid = isAndroid;
148             }
149         }
150     }
151 
stopService()152     public void stopService() {
153         if (mChatService != null) {
154             isServiceRunning = false;
155             mChatService.stop();
156         }
157         new Handler().postDelayed(new Runnable() {
158             public void run() {
159                 if (mChatService != null) {
160                     isServiceRunning = false;
161                     mChatService.stop();
162                 }
163             }
164         }, 500);
165     }
166 
setDeviceTarget(boolean isAndroid)167     public void setDeviceTarget(boolean isAndroid) {
168         stopService();
169         startService(isAndroid);
170         BluetoothSPP.this.isAndroid = isAndroid;
171     }
172 
173     @SuppressLint("HandlerLeak")
174     private final Handler mHandler = new Handler() {
175         public void handleMessage(Message msg) {
176 
177             switch (msg.what) {
178             case BluetoothState.MESSAGE_WRITE:
179                 break;
180             case BluetoothState.MESSAGE_READ:
181             Log.i("DEBUGGER_TAG", "MESSAGE_READ");
182                 byte[] readBuf = (byte[]) msg.obj;
183                 String readMessage = new String(readBuf);
184                 if(readBuf != null && readBuf.length > 0) {
185                     Log.i("DEBUGGER_TAG", readMessage);
186                     if(mDataReceivedListener != null)
187                         mDataReceivedListener.onDataReceived(readBuf, readMessage);
188                 }
189                 break;
190             case BluetoothState.MESSAGE_DEVICE_NAME:
191             Log.i("DEBUGGER_TAG", "MESSAGE_DEVICE_NAME");
192 
193                 mDeviceName = msg.getData().getString(BluetoothState.DEVICE_NAME);
194                 mDeviceAddress = msg.getData().getString(BluetoothState.DEVICE_ADDRESS);
195                 if(mBluetoothConnectionListener != null)
196                     mBluetoothConnectionListener.onDeviceConnected(mDeviceName, mDeviceAddress);
197                 isConnected = true;
198                 break;
199             case BluetoothState.MESSAGE_TOAST:
200             Log.i("DEBUGGER_TAG", "MESSAGE_TOAST");
201                 Toast.makeText(mContext, msg.getData().getString(BluetoothState.TOAST)
202                         , Toast.LENGTH_SHORT).show();
203                 break;
204             case BluetoothState.MESSAGE_STATE_CHANGE:
205             Log.i("DEBUGGER_TAG", "MESSAGE_STATE_CHANGE");
206                 if(mBluetoothStateListener != null)
207                     mBluetoothStateListener.onServiceStateChanged(msg.arg1);
208 
209                 if(msg.arg1 == BluetoothState.STATE_NONE)
210                     Log.i("DEBUGGER_TAG", "State:STATE_NONE");
211                 else if(msg.arg1 == BluetoothState.STATE_LISTEN)
212                     Log.i("DEBUGGER_TAG", "State:STATE_LISTEN");
213                 else if(msg.arg1 == BluetoothState.STATE_CONNECTING)
214                     Log.i("DEBUGGER_TAG", "State:STATE_CONNECTING");
215                 else if(msg.arg1 == BluetoothState.STATE_CONNECTED)
216                     Log.i("DEBUGGER_TAG", "State:STATE_CONNECTED");
217 
218                 if(isConnected && msg.arg1 != BluetoothState.STATE_NONE) {
219                     Log.i("DEBUGGER_TAG", "State:NONE, maybe stop requested?");
220                     isAutoConnectionEnabled = false;
221                 }
222 
223 
224 
225                 if(isConnected && msg.arg1 != BluetoothState.STATE_CONNECTED) {
226                     if(mBluetoothConnectionListener != null)
227                         mBluetoothConnectionListener.onDeviceDisconnected();
228                     if(isAutoConnectionEnabled) {
229                         isAutoConnectionEnabled = false;
230                         autoConnect(keyword);
231                     }
232                     Log.i("DEBUGGER_TAG", "Disconnected");
233                     isConnected = false;
234                     mDeviceName = null;
235                     mDeviceAddress = null;
236                 }
237 
238                 if(!isConnecting && msg.arg1 == BluetoothState.STATE_CONNECTING) {
239                     isConnecting = true;
240                     Log.i("DEBUGGER_TAG", "isConnecting");
241 
242                 } else if(isConnecting) {
243 
244                     if(msg.arg1 == BluetoothState.STATE_CONNECTING) {
245                         Log.i("DEBUGGER_TAG", "stillConnecting");
246                     }
247 
248                     else if(msg.arg1 != BluetoothState.STATE_CONNECTED) {
249                         if(mBluetoothConnectionListener != null)
250                             mBluetoothConnectionListener.onDeviceConnectionFailed();
251                         Log.i("DEBUGGER_TAG", "Connection failed");
252                         isConnecting = false;
253                     }
254                     else{
255                         Log.i("DEBUGGER_TAG", "Connected");
256                         isConnecting = false;
257                     }
258 
259                 }
260                 break;
261             }
262         }
263     };
264 
resetAutoConnect()265     public void resetAutoConnect() {
266         isAutoConnectionEnabled = false;
267     }
268 
connect(Intent data)269     public void connect(Intent data) {
270         String address = data.getExtras().getString(BluetoothState.EXTRA_DEVICE_ADDRESS);
271         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
272         mChatService.connect(device);
273     }
274 
connect(String address)275     public void connect(String address) {
276         Log.i("DEBUGGER_TAG", "connectB " + address);
277         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
278         mChatService.connect(device);
279     }
280 
disconnect()281     public void disconnect() {
282         if(mChatService != null) {
283             isServiceRunning = false;
284             mChatService.stop();
285             if(mChatService.getState() == BluetoothState.STATE_NONE) {
286                 isServiceRunning = true;
287                 mChatService.start(BluetoothSPP.this.isAndroid);
288             }
289         }
290     }
291 
setBluetoothStateListener(BluetoothStateListener listener)292     public void setBluetoothStateListener (BluetoothStateListener listener) {
293         mBluetoothStateListener = listener;
294     }
295 
setOnDataReceivedListener(OnDataReceivedListener listener)296     public void setOnDataReceivedListener (OnDataReceivedListener listener) {
297         mDataReceivedListener = listener;
298     }
299 
setBluetoothConnectionListener(BluetoothConnectionListener listener)300     public void setBluetoothConnectionListener (BluetoothConnectionListener listener) {
301         mBluetoothConnectionListener = listener;
302     }
303 
setAutoConnectionListener(AutoConnectionListener listener)304     public void setAutoConnectionListener(AutoConnectionListener listener) {
305         mAutoConnectionListener = listener;
306     }
307 
enable()308     public void enable() {
309         mBluetoothAdapter.enable();
310     }
311 
send(byte[] data, boolean CRLF)312     public void send(byte[] data, boolean CRLF) {
313         if(mChatService.getState() == BluetoothState.STATE_CONNECTED) {
314             if(CRLF) {
315                 byte[] data2 = new byte[data.length + 2];
316                 for(int i = 0 ; i < data.length ; i++)
317                     data2[i] = data[i];
318                 data2[data2.length - 2] = 0x0A;
319                 data2[data2.length - 1] = 0x0D;
320                 mChatService.write(data2);
321             } else {
322                 mChatService.write(data);
323             }
324         }
325     }
326 
send(String data, boolean CRLF)327     public void send(String data, boolean CRLF) {
328         if(mChatService.getState() == BluetoothState.STATE_CONNECTED) {
329             if(CRLF)
330                 data += "\r\n";
331             mChatService.write(data.getBytes());
332         }
333     }
334 
getConnectedDeviceName()335     public String getConnectedDeviceName() {
336         return mDeviceName;
337     }
338 
getConnectedDeviceAddress()339     public String getConnectedDeviceAddress() {
340         return mDeviceAddress;
341     }
342 
getPairedDeviceName()343     public String[] getPairedDeviceName() {
344         int c = 0;
345         Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
346         String[] name_list = new String[devices.size()];
347         for(BluetoothDevice device : devices) {
348             Log.i("DEBUGGER_TAG", "autoconn name" +  device.getName());
349             name_list[c] = device.getName();
350             c++;
351         }
352         return name_list;
353     }
354 
getPairedDeviceAddress()355     public String[] getPairedDeviceAddress() {
356         int c = 0;
357         Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
358         String[] address_list = new String[devices.size()];
359         for(BluetoothDevice device : devices) {
360             Log.i("DEBUGGER_TAG", "autoconn address" +  device.getAddress());
361             address_list[c] = device.getAddress();
362             c++;
363         }
364         return address_list;
365     }
366 
367 
autoConnect(String keywordName)368     public void autoConnect(String keywordName) {
369         Log.i("DEBUGGER_TAG", "autoconnA");
370         if(!isAutoConnectionEnabled) {
371             Log.i("DEBUGGER_TAG", "autoconnB");
372             keyword = keywordName;
373             isAutoConnectionEnabled = true;
374             isAutoConnecting = true;
375             if(mAutoConnectionListener != null)
376                 mAutoConnectionListener.onAutoConnectionStarted();
377             final ArrayList<String> arr_filter_address = new ArrayList<String>();
378             final ArrayList<String> arr_filter_name = new ArrayList<String>();
379             String[] arr_name = getPairedDeviceName();
380             String[] arr_address = getPairedDeviceAddress();
381             for(int i = 0 ; i < arr_name.length ; i++) {
382                 if(arr_name[i].contains(keywordName)) {
383                     Log.i("DEBUGGER_TAG", "autoconn filter" + arr_address[i]);
384                     arr_filter_address.add(arr_address[i]);
385                     arr_filter_name.add(arr_name[i]);
386                 }
387             }
388 
389             bcl = new BluetoothConnectionListener() {
390                 public void onDeviceConnected(String name, String address) {
391                     bcl = null;
392                     isAutoConnecting = false;
393                 }
394 
395                 public void onDeviceDisconnected() { }
396                 public void onDeviceConnectionFailed() {
397                 	Log.e("CHeck", "Failed");
398                     if(isServiceRunning) {
399                         if(isAutoConnectionEnabled) {
400                             c++;
401                             if(c >= arr_filter_address.size())
402                                 c = 0;
403                             connect(arr_filter_address.get(c));
404                         	Log.e("CHeck", "Connect");
405                             if(mAutoConnectionListener != null)
406                                 mAutoConnectionListener.onNewConnection(arr_filter_name.get(c)
407                                     , arr_filter_address.get(c));
408                         } else {
409                             bcl = null;
410                             isAutoConnecting = false;
411                         }
412                     }
413                 }
414             };
415 
416             setBluetoothConnectionListener(bcl);
417             c = 0;
418             if(mAutoConnectionListener != null)
419                 mAutoConnectionListener.onNewConnection(arr_name[c], arr_address[c]);
420             if(arr_filter_address.size() > 0){
421                 Log.i("DEBUGGER_TAG", "autoconn" + arr_filter_address.get(c));
422                 connect(arr_filter_address.get(c));
423             }
424             else
425                 Toast.makeText(mContext, "Device name mismatch", Toast.LENGTH_SHORT).show();
426         }
427     }
428 
autoConnectAddress(String address)429     public void autoConnectAddress(String address) {
430         Log.i("DEBUGGER_TAG", "autoconnA");
431         if(!isAutoConnectionEnabled) {
432             Log.i("DEBUGGER_TAG", "autoconnB");
433             autoAddress = address;
434             isAutoConnectionEnabled = true;
435             isAutoConnecting = true;
436             if(mAutoConnectionListener != null)
437                 mAutoConnectionListener.onAutoConnectionStarted();
438 
439             bcl = new BluetoothConnectionListener() {
440                 public void onDeviceConnected(String name, String address) {
441                     bcl = null;
442                     isAutoConnecting = false;
443                 }
444 
445                 public void onDeviceDisconnected() { }
446                 public void onDeviceConnectionFailed() {
447                         Log.e("CHeck", "Failed");
448                     if(isServiceRunning) {
449                         if(isAutoConnectionEnabled) {
450                              connect(autoAddress);
451                              Log.e("CHeck", "Connect");
452                             if(mAutoConnectionListener != null)
453                                 mAutoConnectionListener.onNewConnection(autoAddress, autoAddress);
454                         } else {
455                             bcl = null;
456                             isAutoConnecting = false;
457                         }
458                     }
459                 }
460             };
461 
462             setBluetoothConnectionListener(bcl);
463 
464             if(mAutoConnectionListener != null)
465                 mAutoConnectionListener.onNewConnection(autoAddress, autoAddress);
466              connect(address);
467 
468         }
469     }
470 
471 }
472