88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/APIDemo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/APIDemo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 31
5 | defaultConfig {
6 | multiDexEnabled false
7 | minSdkVersion 24
8 | }
9 | buildTypes {
10 | release {
11 | minifyEnabled false
12 | }
13 | }
14 | }
15 | repositories {
16 | google()
17 | }
18 | allprojects {
19 | repositories {
20 | google()
21 | }
22 | }
23 | dependencies {
24 | implementation fileTree(include: ['*.jar'], dir: 'libs')
25 | implementation 'androidx.activity:activity:1.4.0'
26 | implementation 'androidx.fragment:fragment:1.4.1'
27 | implementation files('libs/bluefire-api-v27.0.aar')
28 |
29 | }
--------------------------------------------------------------------------------
/APIDemo/libs/bluefire-api-v27.0.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueFire-LLC/BlueFire-API-for-Android-Studio/62d5696102f6bcefa3ec0cd9b0b1f965f81ab739/APIDemo/libs/bluefire-api-v27.0.aar
--------------------------------------------------------------------------------
/APIDemo/libs/commons-codec-1.10.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueFire-LLC/BlueFire-API-for-Android-Studio/62d5696102f6bcefa3ec0cd9b0b1f965f81ab739/APIDemo/libs/commons-codec-1.10.jar
--------------------------------------------------------------------------------
/APIDemo/libs/commons-lang3-3.3.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueFire-LLC/BlueFire-API-for-Android-Studio/62d5696102f6bcefa3ec0cd9b0b1f965f81ab739/APIDemo/libs/commons-lang3-3.3.2.jar
--------------------------------------------------------------------------------
/APIDemo/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\Mark\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/APIDemo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/APIDemo/src/main/java/com/bluefire/apidemo/Comm.java:
--------------------------------------------------------------------------------
1 | package com.bluefire.apidemo;
2 |
3 | import android.bluetooth.BluetoothAdapter;
4 | import android.content.Context;
5 | import android.os.Handler;
6 | import android.os.Message;
7 |
8 | import com.bluefire.api.BFComm;
9 | import com.bluefire.api.BlueFire;
10 | import com.bluefire.api.ConnectionStates;
11 | import com.bluefire.api.Const;
12 | import com.bluefire.api.Helper;
13 |
14 | import java.io.IOException;
15 | import java.util.LinkedList;
16 | import java.util.Queue;
17 | import java.util.Timer;
18 | import java.util.TimerTask;
19 |
20 | public class Comm extends BFComm
21 | {
22 | //region Declaratives
23 |
24 | // Android specific
25 | protected Context Context;
26 | protected Handler ConnectionHandler;
27 |
28 | protected String DeviceName = "";
29 | protected String DeviceAddress = "";
30 |
31 | protected String BFDeviceName = "";
32 |
33 | private boolean IsClearingInputPackets;
34 | private Queue InputPackets = new LinkedList();;
35 |
36 | private boolean IsQueueingData;
37 | protected boolean IsSendingData;
38 | private boolean IsClearingSendBuffer;
39 | private Queue SendBuffer = new LinkedList();
40 |
41 | private Timer DisconnectTimer;
42 | private int WaitForDisconnectTime = 8 * Const.OneSecond;
43 |
44 | private String CommMessage = "";
45 | protected ConnectionStates ConnectionState = ConnectionStates.NA;
46 | private ConnectionStates CurrentState = ConnectionStates.NotConnected; // needs to be NotConnected
47 |
48 | private Queue StateQueue = new LinkedList();
49 | private UpdateStateThreading UpdateStateThread;
50 |
51 | protected BluetoothAdapter BTAdapter;
52 |
53 | protected BlueFire blueFire;
54 |
55 | //endregion
56 |
57 | //region Valid Adapter
58 |
59 | protected Boolean IsValidAdapter()
60 | {
61 | return IsValidAdapter(DeviceName, DeviceAddress);
62 | }
63 |
64 | protected boolean IsValidAdapter(String BTDeviceName, String BTDeviceAddress)
65 | {
66 | // Check for a last connected device
67 | if (IsLastConnectedAdapterSet() && !BTDeviceAddress.equals("") && BTDeviceAddress.equals(blueFire.AdapterId()))
68 | return true;
69 |
70 | // Check for not finding a last connected device
71 | else if (IsLastConnectedAdapterSet())
72 | return false;
73 |
74 | // Check for a BlueFire device
75 | else if (BTDeviceName.equals(BFDeviceName))
76 | return true;
77 |
78 | return false;
79 | }
80 |
81 | //endregion
82 |
83 | //region Last Connected Adapter
84 |
85 | // IsLastConnectedId Property
86 | protected boolean IsLastConnectedAdapter()
87 | {
88 | return IsLastConnectedAdapter(DeviceAddress);
89 | }
90 |
91 | // IsLastConnectedId Property
92 | protected boolean IsLastConnectedAdapter(String BTDeviceAddress)
93 | {
94 | return ((blueFire.ConnectToLastAdapter() || blueFire.SecureAdapter()) && BTDeviceAddress.equals(blueFire.AdapterId()));
95 | }
96 |
97 | protected boolean IsLastConnectedAdapterSet()
98 | {
99 | return ((blueFire.ConnectToLastAdapter() || blueFire.SecureAdapter()) && !blueFire.AdapterId().equals(""));
100 | }
101 |
102 | //endregion
103 |
104 | //region Timeout
105 |
106 | private boolean AdapterIsBusy;
107 | private boolean IsDataTimedOut = false;
108 | private long PrevDataTime = Helper.GetDateTimeNowMs();
109 |
110 | private void ResetTimeOut()
111 | {
112 | IsDataTimedOut = false;
113 |
114 | PrevDataTime = Helper.GetDateTimeNowMs();
115 | }
116 |
117 | protected boolean CheckDataTimeOut()
118 | {
119 | // No data, check for timeout
120 | // Note, only timeout once a cycle
121 | if (!IsDataTimedOut)
122 | {
123 | // Check if the adapter is busy
124 | if (blueFire.BusyWaitTime > 0)
125 | {
126 | if (!AdapterIsBusy)
127 | {
128 | AdapterIsBusy = true;
129 | ResetTimeOut();
130 | }
131 | }
132 | else
133 | {
134 | if (AdapterIsBusy)
135 | {
136 | AdapterIsBusy = false;
137 | ResetTimeOut();
138 | }
139 | }
140 |
141 | // Check for a data timeout
142 | if (Helper.TimeDiff(PrevDataTime) > blueFire.DataTimeoutInterval)
143 | {
144 | IsDataTimedOut = true;
145 | return true;
146 | }
147 | }
148 | return false;
149 | }
150 |
151 | //endregion
152 |
153 | //region Constructor
154 |
155 | public Comm(Context context, Handler connectionHandler, BlueFire blueFire)
156 | {
157 | Context = context;
158 |
159 | ConnectionHandler = connectionHandler;
160 |
161 | this.blueFire = blueFire;
162 |
163 | UpdateStateThread = new UpdateStateThreading();
164 | UpdateStateThread.start();
165 | }
166 |
167 | //endregion
168 |
169 | //region Bluetooth
170 |
171 | private boolean EnableBluetooth()
172 | {
173 | try
174 | {
175 | // Initializes a Bluetooth adapter.
176 | BTAdapter = BluetoothAdapter.getDefaultAdapter();
177 |
178 | if (BTAdapter == null)
179 | return false;
180 |
181 | if (!BTAdapter.isEnabled())
182 | return TurnBluetoothOn();
183 |
184 | return true;
185 | }
186 | catch (Exception ex)
187 | {
188 | RaiseSystemError("CommBLE EnableBluetooth", ex);
189 | return false;
190 | }
191 | }
192 |
193 | protected boolean TurnBluetoothOn()
194 | {
195 | try
196 | {
197 | if (BTAdapter == null)
198 | return false;
199 |
200 | // Bluetooth is not on, turn it on
201 | BTAdapter.enable();
202 |
203 | // Wait for Bluetooth to turn on
204 | int WaitTime = 3 * Const.OneSecond;
205 | while (!BTAdapter.isEnabled())
206 | {
207 | Helper.Sleep(100);
208 | WaitTime -= 100;
209 | if (WaitTime <= 0)
210 | break;
211 | }
212 | if (!BTAdapter.isEnabled())
213 | return false;
214 |
215 | Helper.Sleep(100); // allow bluetooth to initialize itself
216 |
217 | return true;
218 |
219 | } catch (Exception ex)
220 | {
221 | RaiseSystemError ("CommBT2.TurnBluetoothOn", ex);
222 | return false;
223 | }
224 | }
225 |
226 | protected void TurnBluetoothOff()
227 | {
228 | if (BTAdapter == null)
229 | return;
230 |
231 | BTAdapter.disable();
232 |
233 | // Wait for Bluetooth to turn off
234 | int WaitTime = 3 * Const.OneSecond;
235 | while (BTAdapter.isEnabled())
236 | {
237 | Helper.Sleep(100);
238 | WaitTime -= 100;
239 | if (WaitTime <= 0)
240 | break;
241 | }
242 |
243 | Helper.Sleep(100); // allow bluetooth to initialize itself
244 | }
245 |
246 | private boolean RecycleBluetooth()
247 | {
248 | TurnBluetoothOff();
249 |
250 | if (!TurnBluetoothOn())
251 | return false;
252 | else
253 | Helper.Sleep(3 * Const.OneSecond); // give Bluetooth time to find the adapter
254 |
255 | return true;
256 | }
257 |
258 | //endregion
259 |
260 | //region Initialization
261 |
262 | // Override in CommBLE/CommBT2
263 | protected void Initialize()
264 | {
265 | }
266 |
267 | private void InitializeData(boolean isReconnecting)
268 | {
269 | ClearSendBuffer();
270 | ClearInputPackets();
271 |
272 | PreviousId = "";
273 |
274 | IsConnected = false;
275 | IsSendingData = false;
276 |
277 | blueFire.BusyWaitTime = 0;
278 |
279 | if (!isReconnecting)
280 | {
281 | IsReconnecting = false;
282 | ReconnectAttempt = 0;
283 | }
284 | }
285 |
286 | private void InitializeState()
287 | {
288 | StateQueue.clear();
289 | }
290 |
291 | private void InitializeComm()
292 | {
293 | UpdateState(ConnectionStates.Initializing);
294 |
295 | Initialize();
296 |
297 | UpdateState(ConnectionStates.Initialized);
298 | }
299 |
300 | //endregion
301 |
302 | //region Connection
303 |
304 | // Connect method
305 | @Override
306 | public boolean Connect()
307 | {
308 | return Connect(false);
309 | }
310 | private boolean Connect(boolean isReconnecting)
311 | {
312 | InitializeData(isReconnecting);
313 |
314 | if (!isReconnecting)
315 | InitializeState();
316 |
317 | InitializeComm();
318 |
319 | if (!isReconnecting)
320 | UpdateState(ConnectionStates.Connecting);
321 | else
322 | UpdateState(ConnectionStates.Reconnecting);
323 |
324 | if (!StartConnection()) // this will block
325 | AdapterNotConnected();
326 |
327 | return (ConnectionState == ConnectionStates.Connected);
328 | }
329 |
330 | // Override in CommBLE/CommBT2
331 | protected boolean StartConnection()
332 | {
333 | return InitializeConnection();
334 | }
335 |
336 | protected boolean InitializeConnection()
337 | {
338 | IsConnected = false;
339 | IsConnecting = true;
340 |
341 | ClearInputPackets();
342 |
343 | if (!EnableBluetooth())
344 | return false;
345 |
346 | return true;
347 | }
348 |
349 | // Override in CommBLE/CommBT2
350 | protected void AdapterConnected()
351 | {
352 | IsConnecting = false;
353 | IsConnected = true;
354 |
355 | AdapterId = DeviceAddress;
356 |
357 | ResetTimeOut();
358 |
359 | // Check for reconnecting
360 | if (IsReconnecting)
361 | AdapterReconnected();
362 | else
363 | UpdateState(ConnectionStates.Connected);
364 | }
365 |
366 | // Override in CommBLE/CommBT2
367 | protected void AdapterNotConnected()
368 | {
369 | try
370 | {
371 | IsConnecting = false;
372 | IsConnected = false;
373 |
374 | Disconnect();
375 |
376 | if (IsReconnecting)
377 | Reconnect();
378 | else
379 | UpdateState(ConnectionStates.NotConnected);
380 | }
381 | catch (Exception ex){}
382 | }
383 |
384 | //endregion
385 |
386 | //region Reconnection
387 |
388 | public boolean Reconnect()
389 | {
390 | // Check for no reconnect attempts or non-compatible adapter
391 | if (blueFire.MaxReconnectAttempts() == 0 || !blueFire.IsCompatible())
392 | {
393 | StopReconnection(true);
394 | return false;
395 | }
396 |
397 | // Check for exceeding reconnect attempts
398 | if (ReconnectAttempt >= blueFire.MaxReconnectAttempts())
399 | {
400 | AdapterNotReconnected();
401 | return false;
402 | }
403 |
404 | // Set for reconnecting
405 | IsReconnecting = true;
406 |
407 | ReconnectAttempt++;
408 |
409 | // android.util.Log.d("BlueFire", "Reconnect, Attempt=" + ReconnectAttempts);
410 |
411 | // Check for recycling Bluetooth.
412 | // Note, must be before Dispose.
413 | if (ReconnectAttempt == (blueFire.BluetoothRecycleAttempt()))
414 | {
415 | if (!RecycleBluetooth())
416 | ReconnectAttempt = blueFire.MaxReconnectAttempts();
417 | }
418 |
419 | // Try to reconnect
420 | return Connect(IsReconnecting);
421 | }
422 |
423 | public void StopReconnection(boolean DisconnectAdapter)
424 | {
425 | IsReconnecting = false;
426 |
427 | if (DisconnectAdapter)
428 | Disconnect();
429 | }
430 |
431 | private void AdapterReconnected()
432 | {
433 | StopReconnection(false);
434 |
435 | IsReconnecting = false;
436 |
437 | UpdateState(ConnectionStates.Reconnected);
438 | }
439 |
440 | private void AdapterNotReconnected()
441 | {
442 | StopReconnection(true);
443 |
444 | ConnectionStates State;
445 |
446 | if (IsConnecting)
447 | State = ConnectionStates.NotConnected;
448 | else
449 | State = ConnectionStates.NotReconnected;
450 |
451 | AdapterNotConnected();
452 |
453 | UpdateState(State);
454 | }
455 |
456 | //endregion
457 |
458 | //region Disconnection
459 |
460 | // Disconnect Method
461 | // Override in CommBLE/CommBT2
462 | protected boolean Disconnect()
463 | {
464 | return Disconnect(false);
465 | }
466 | @Override
467 | public boolean Disconnect(boolean WaitForDisconnect)
468 | {
469 | try
470 | {
471 | if (ConnectionState == ConnectionStates.Disconnecting || ConnectionState == ConnectionStates.Disconnected)
472 | return false;
473 |
474 | InitializeData(IsReconnecting);
475 |
476 | return true;
477 | }
478 | catch (Exception ex)
479 | {
480 | RaiseSystemError("Comm.Disconnect", ex);
481 | return false;
482 | }
483 | }
484 |
485 | protected void CheckWaitForDisconnect(boolean WaitForDisconnect)
486 | {
487 | if (WaitForDisconnect)
488 | {
489 | DisconnectTimer = new Timer();
490 | DisconnectTimer.schedule(new DisconnectTimedOut(), WaitForDisconnectTime, Long.MAX_VALUE);
491 | }
492 | else
493 | UpdateState(ConnectionStates.Disconnected);
494 | }
495 |
496 | private class DisconnectTimedOut extends TimerTask
497 | {
498 | @Override
499 | public void run()
500 | {
501 | UpdateState(ConnectionStates.Disconnected);
502 | }
503 | };
504 |
505 | //endregion
506 |
507 | //region Get Data
508 |
509 | @Override
510 | public boolean IsDataAvailable()
511 | {
512 | if (InputPackets.size() > 0)
513 | return true;
514 |
515 | if (CheckDataTimeOut())
516 | RaiseDataTimeout();
517 |
518 | return false;
519 | }
520 |
521 | // Get message data from the adapter
522 | // The data stream looks like:
523 | // Length (2) - Length of Requested Data, not Checksum
524 | // Length Checksum (1)
525 | // Message Data (n)
526 | // Data Checksum (1)
527 | //
528 | @Override
529 | public byte[] GetData()
530 | {
531 | try
532 | {
533 | if (!IsDataAvailable())
534 | return new byte[0];
535 |
536 | byte[] DataBuffer = null;
537 | try
538 | {
539 | DataBuffer = (byte[]) InputPackets.poll();
540 | }
541 | catch (Exception ex){ }
542 |
543 | if (DataBuffer == null) // just in case ...
544 | return new byte[0];
545 |
546 | // Check for an invalid length and ignore the packet
547 | if (!IsValidDataLength(DataBuffer))
548 | return new byte[0];
549 |
550 | // Check for a checksum error and ignore the packet
551 | byte[] MessageData = GetMessageData(DataBuffer);
552 | if (MessageData == null)
553 | return new byte[0];
554 |
555 | // Return the message data
556 | return MessageData;
557 | }
558 | catch (Exception ex)
559 | {
560 | RaiseDataError("Comm.GetData", ex);
561 | return null;
562 | }
563 | }
564 |
565 | // Get the data length from the adapter message
566 | protected int GetDataLength(byte[] DataBuffer)
567 | {
568 | try
569 | {
570 | if (DataBuffer.length < 3)
571 | return -1;
572 |
573 | // Get and check the message length
574 | int Length1 = DataBuffer[0];
575 | int Length2 = DataBuffer[1];
576 | int Length3 = DataBuffer[2];
577 |
578 | // Check the length bytes
579 | if (Length3 != (byte)(Length1 ^ Length2))
580 | {
581 | // Don't log this error because it can occur quite often when the data rate is high
582 | //Helper.LogMessage("Comm.GetDataLength - Packet Data Length Error - Invalid Length");
583 | return -1;
584 | }
585 |
586 | // Get the message data length
587 | int DataLength = (Length1 << 8) | Length2;
588 | if (DataLength < 0)
589 | {
590 | // Don't log this error because it can occur quite often when the data rate is high
591 | //Helper.LogMessage("Comm.GetDataLength - Packet Data Length Error - Negative Length");
592 | return -1;
593 | }
594 |
595 | return DataLength;
596 | }
597 | catch (Exception ex)
598 | {
599 | RaiseDataError("Comm.GetDataLength", ex);
600 | return -1;
601 | }
602 | }
603 |
604 | // Get the data length from the adapter message
605 | protected boolean IsValidDataLength(byte[] DataBuffer)
606 | {
607 | try
608 | {
609 | // Get the message data length
610 | int DataLength = GetDataLength(DataBuffer);
611 | if (DataLength < 0)
612 | return false;
613 |
614 | // Validate the data length.
615 | // StartIndex(3) + Data Length + Checksum(1) must be <= to DataBuffer Length
616 | if ((StartIndex + DataLength + 1) > DataBuffer.length)
617 | {
618 | // Don't log this error because it can occur quite often when the data rate is high
619 | //Helper.LogMessage("Comm.IsValidDataLength - Packet Data Length Error - Length Too Long, DataLength=" + DataLength + ", BufferLength=" + DataBuffer.Length);
620 | return false;
621 | }
622 |
623 | return true;
624 | }
625 | catch (Exception ex)
626 | {
627 | RaiseDataError("Comm.IsValidDataLength", ex);
628 | return false;
629 | }
630 | }
631 |
632 | // Get the message data from the adapter message
633 | private byte[] GetMessageData(byte[] DataBuffer)
634 | {
635 | try
636 | {
637 | // Get the data length
638 | int DataLength = GetDataLength(DataBuffer);
639 |
640 | // Validate checksum on the message data
641 | byte Checksum = Helper.CalcChecksum(DataBuffer, StartIndex, DataLength);
642 | if (Checksum != DataBuffer[StartIndex + DataLength])
643 | {
644 | return null;
645 | }
646 |
647 | // Return the message data (excluding the checksum)
648 | byte[] MessageData = new byte[DataLength];
649 | System.arraycopy(DataBuffer, StartIndex, MessageData, 0, DataLength);
650 |
651 | return MessageData;
652 | }
653 | catch (Exception ex)
654 | {
655 | RaiseDataError("Comm.GetMessageData", ex);
656 | return null;
657 | }
658 | }
659 |
660 | //endregion
661 |
662 | //region Send Adapter Data
663 |
664 | @Override
665 | public void SendData(byte[] DataBuffer)
666 | {
667 | int DataIndex = 0;
668 | int DataLength;
669 | byte[] SendBuffer;
670 |
671 | try
672 | {
673 | if (DataBuffer.length == 0)
674 | return;
675 |
676 | // Get the length of data to send
677 | DataLength = DataBuffer.length;
678 |
679 | // Build the data stream to send the data.
680 | // Include space for Length and Checksum.
681 | SendBuffer = new byte[2 + DataLength + 1]; // Length Bytes + Data + CheckSum
682 |
683 | // Include the data length in the send buffer.
684 | // Start calculating the checksum.
685 | byte[] LengthBytes = Helper.Short2Bytes(DataLength);
686 | SendBuffer[DataIndex] = LengthBytes[0];
687 | SendBuffer[DataIndex + 1] = LengthBytes[1];
688 | int Checksum = Helper.JavaUnsignedByte(SendBuffer[DataIndex]) + Helper.JavaUnsignedByte(SendBuffer[DataIndex + 1]); // checksum
689 | DataIndex += 2;
690 |
691 | // Include the data in the send buffer
692 | for (int i = 0; i < DataLength; i++)
693 | {
694 | SendBuffer[DataIndex] = DataBuffer[i];
695 | Checksum += Helper.JavaUnsignedByte(DataBuffer[i]);
696 | DataIndex++;
697 | }
698 |
699 | // Calculate the Checksum and store it at the end of the send buffer
700 | SendBuffer[DataIndex] = (byte)(Helper.GenerateChecksum(Checksum));
701 |
702 | // Send the request for data
703 | AddSendBuffer(SendBuffer);
704 | }
705 | catch (Exception ex)
706 | {
707 | ClearSendBuffer();
708 | RaiseDataError("Comm.SendPID", ex);
709 | return;
710 | }
711 | }
712 |
713 | protected void AddSendBuffer(byte[] DataBuffer)
714 | {
715 | try
716 | {
717 | while (IsSendingData || IsClearingSendBuffer)
718 | Helper.Sleep(10);
719 |
720 | if (SendBuffer == null) // Comm null while waiting for IsSendingData
721 | return;
722 |
723 | IsQueueingData = true;
724 |
725 | SendBuffer.add(DataBuffer);
726 | }
727 | catch (Exception ex)
728 | {
729 | int BufferCount = SendBuffer.size();
730 | ClearSendBuffer();
731 | RaiseDataError("Comm.AddSendBuffer, Buffer Size=" + BufferCount, ex);
732 | }
733 |
734 | IsQueueingData = false;
735 | }
736 |
737 | private void ClearSendBuffer()
738 | {
739 | IsClearingSendBuffer = true;
740 |
741 | try
742 | {
743 | SendBuffer.clear();
744 | }
745 | catch (Exception ex) { } // Android can throw an exception
746 |
747 | IsClearingSendBuffer = false;
748 | }
749 |
750 | // Check if there is data in the buffer and send it
751 | @Override
752 | public void CheckSendBuffer()
753 | {
754 | try
755 | {
756 | if (!IsConnected)
757 | return;
758 |
759 | // Ignore if writing data to the buffer
760 | if (IsSendingData)
761 | return;
762 |
763 | if (IsClearingSendBuffer)
764 | return;
765 |
766 | if (blueFire.BusyWaitTime > 0)
767 | return;
768 |
769 | if (SendBuffer.isEmpty())
770 | return;
771 |
772 | while (IsQueueingData)
773 | Helper.Sleep(10);
774 |
775 | if (SendBuffer == null) // Comm null while waiting for IsQueueingData
776 | return;
777 |
778 | IsSendingData = true;
779 |
780 | byte[] DataBuffer = (byte[])SendBuffer.poll();
781 |
782 | // Ignore if not connected or no data
783 | if (!IsConnected || DataBuffer == null || DataBuffer.length == 0)
784 | {
785 | IsSendingData = false;
786 | return;
787 | }
788 |
789 | SendAdapterData(DataBuffer, DataBuffer.length);
790 | }
791 | catch (IOException ex) { } // This occurs when going out of BT range
792 | catch (Exception ex)
793 | {
794 | RaiseDataError("Comm.CheckSendBuffer", ex);
795 | }
796 |
797 | IsSendingData = false;
798 | }
799 |
800 | // Send Adapter Data Method
801 | protected boolean SendAdapterData(byte[] DataBuffer, int DataLength) throws Exception
802 | {
803 | if (!IsConnected)
804 | return false;
805 |
806 | return true;
807 | }
808 |
809 | //endregion
810 |
811 | //region Receive Adapter Data
812 |
813 | // Queue the input data for processing.
814 | // The data stream looks like:
815 | // Length (2) - Length of Requested Data, not Checksum
816 | // Length Checksum (1)
817 | // Message Data (n)
818 | // Data Checksum (1)
819 | protected void ReceiveAdapterData(byte[] DataBuffer)
820 | {
821 | try
822 | {
823 | if (DataBuffer.length == 0) // should not occur but just in case ...
824 | return;
825 |
826 | // Reset data timeout
827 | ResetTimeOut();
828 |
829 | blueFire.BusyWaitTime = 0;
830 |
831 | // Queue the data for processing later
832 | while (IsClearingInputPackets)
833 | Helper.Sleep(10);
834 |
835 | if (InputPackets == null) // Comm null while waiting for IsSendingData
836 | return;
837 |
838 | // Limit number of input packets
839 | if (InputPackets.size() > blueFire.MaxCommBuffer())
840 | ClearInputPackets();
841 |
842 | try
843 | {
844 | InputPackets.add(DataBuffer);
845 | }
846 | catch (Exception ex) {}
847 | }
848 | catch (Exception ex)
849 | {
850 | ClearInputPackets();
851 | }
852 | }
853 |
854 | protected void ClearInputPackets()
855 | {
856 | IsClearingInputPackets = true;
857 |
858 | try
859 | {
860 | InputPackets.clear();
861 | }
862 | catch (Exception ex){ } // Android can throw an exception
863 |
864 | IsClearingInputPackets = false;
865 | }
866 |
867 | //endregion
868 |
869 | //region Raise Events
870 |
871 | protected void RaiseNotification(String Location, String Message)
872 | {
873 | RaiseNotification(Location, Message, false);
874 | }
875 | protected void RaiseNotification(String Location, String Message, boolean Force)
876 | {
877 | if (!Location.equals(""))
878 | Message = Location + " - " + Message;
879 |
880 | if (!blueFire.NotificationsOn() && !Force)
881 | return;
882 |
883 | // Save previous connection state
884 | ConnectionStates CurrentState = ConnectionState;
885 |
886 | // Notify the app
887 | UpdateState(ConnectionStates.Notification, Message);
888 |
889 | // Restore connection state
890 | ConnectionState = CurrentState;
891 | }
892 |
893 | // Raise Data Timeout
894 | protected void RaiseDataTimeout()
895 | {
896 | UpdateState(ConnectionStates.DataTimeout);
897 |
898 | Reconnect();
899 | }
900 |
901 | // Raise Data Error
902 | protected void RaiseDataError(String Message)
903 | {
904 | RaiseDataError(Message, null);
905 |
906 | Reconnect();
907 | }
908 |
909 | private void RaiseDataError(String Message, Exception ex)
910 | {
911 | Message = Helper.GetErrorMessage("", Message, ex);
912 |
913 | UpdateState(ConnectionStates.DataError, Message);
914 |
915 | Reconnect();
916 | }
917 |
918 | // Raise System Error
919 | protected void RaiseSystemError(String Location, String Message)
920 | {
921 | RaiseSystemError(Location, Message, null);
922 | }
923 |
924 | protected void RaiseSystemError(String Location, Exception ex)
925 | {
926 | RaiseSystemError(Location, "", ex);
927 | }
928 |
929 | protected void RaiseSystemError(String Location, String Message, Exception ex)
930 | {
931 | Message = Helper.GetErrorMessage(Location, Message, ex);
932 |
933 | UpdateState(ConnectionStates.SystemError, Message);
934 | }
935 |
936 | //endregion
937 |
938 | //region Update State
939 |
940 | protected void UpdateState(ConnectionStates State)
941 | {
942 | UpdateState(State, "");
943 | }
944 | private void UpdateState(ConnectionStates State, String Message)
945 | {
946 | //Helper.LogMessage("Comm UpdateState, Queued State=" + State);
947 |
948 | Message HandleMessage = new Message();
949 | HandleMessage.what = State.ordinal();
950 | HandleMessage.obj = Message;
951 |
952 | ConnectionState = ConnectionStates.values()[HandleMessage.what];
953 | CommMessage = (String)HandleMessage.obj;
954 |
955 | StateQueue.add(HandleMessage);
956 | }
957 |
958 | private class UpdateStateThreading extends Thread
959 | {
960 | public void run()
961 | {
962 | try
963 | {
964 | int Retry = blueFire.EventHandlerRetry;
965 |
966 | while (true)
967 | {
968 | if (!StateQueue.isEmpty())
969 | {
970 | // if (StateQueue.size() > 1)
971 | // Helper.LogMessage("Comm UpdateStateThreading, StateQueue Size=" + StateQueue.size());
972 |
973 | Message HandleMessage = StateQueue.peek(); // get message
974 | if (HandleMessage != null)
975 | {
976 | ConnectionStates CommState = ConnectionStates.values()[HandleMessage.what];
977 | String CommMessage = (String) HandleMessage.obj;
978 |
979 | //Helper.LogMessage("Comm UpdateStateThreading, Sending State=" + ConnectionState);
980 |
981 | ConnectionHandler.obtainMessage(CommState.ordinal(), CommMessage).sendToTarget();
982 |
983 | boolean MessageReceived = !ConnectionHandler.hasMessages(CommState.ordinal(), CommMessage);
984 | if (!MessageReceived) // check if message received
985 | {
986 | int Delay = 0;
987 | while (Delay < blueFire.EventHandlerDelay && !MessageReceived)
988 | {
989 | Helper.Sleep(10);
990 | Delay += 10;
991 | MessageReceived = !ConnectionHandler.hasMessages(CommState.ordinal(), CommMessage);
992 | }
993 | if (!MessageReceived)
994 | {
995 | Helper.LogMessage("Comm UpdateStateThreading, ***** Missing State=" + CommState + " *****");
996 | ConnectionHandler.removeMessages(CommState.ordinal(), CommMessage); // remove sent message
997 | Retry -= blueFire.EventHandlerDelay;
998 | if (Retry <= 0)
999 | {
1000 | Helper.LogMessage("Comm UpdateStateThreading, ***** Ignoring State=" + CommState + " *****");
1001 | Retry = blueFire.EventHandlerRetry;
1002 | MessageReceived = true; // set ignored message as received so it can be removed from the queue
1003 | }
1004 | }
1005 | }
1006 | if (MessageReceived)
1007 | StateQueue.poll(); // remove message
1008 | }
1009 | }
1010 | Helper.Sleep(1); // allow other threads to execute
1011 | }
1012 | }
1013 | catch (Exception ex)
1014 | {
1015 | RaiseDataError("Comm.UpdateStateThreading", ex);
1016 | }
1017 | }
1018 | }
1019 |
1020 | //endregion
1021 |
1022 | //region Dispose
1023 |
1024 | @Override
1025 | public void Dispose()
1026 | {
1027 | try
1028 | {
1029 | Disconnect();
1030 | }
1031 | catch (Exception ex)
1032 | {
1033 | }
1034 | }
1035 |
1036 | //endregion
1037 | }
1038 |
--------------------------------------------------------------------------------
/APIDemo/src/main/java/com/bluefire/apidemo/CommBLE.java:
--------------------------------------------------------------------------------
1 | package com.bluefire.apidemo;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 | import android.bluetooth.BluetoothGatt;
5 | import android.bluetooth.BluetoothGattCallback;
6 | import android.bluetooth.BluetoothGattCharacteristic;
7 | import android.bluetooth.BluetoothGattDescriptor;
8 | import android.bluetooth.BluetoothGattService;
9 | import android.bluetooth.BluetoothProfile;
10 | import android.bluetooth.le.BluetoothLeScanner;
11 | import android.bluetooth.le.ScanCallback;
12 | import android.bluetooth.le.ScanFilter;
13 | import android.bluetooth.le.ScanResult;
14 | import android.bluetooth.le.ScanSettings;
15 | import android.bluetooth.le.ScanSettings.Builder;
16 | import android.content.Context;
17 | import android.os.Handler;
18 |
19 | import com.bluefire.api.BFCommBLE;
20 | import com.bluefire.api.BlueFire;
21 | import com.bluefire.api.ConnectionStates;
22 | import com.bluefire.api.Const;
23 | import com.bluefire.api.Helper;
24 |
25 | import java.util.ArrayList;
26 | import java.util.List;
27 | import java.util.Timer;
28 | import java.util.TimerTask;
29 | import java.util.UUID;
30 |
31 | import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
32 | import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
33 |
34 | public class CommBLE extends Comm
35 | {
36 | //region Declaratives
37 |
38 | private BluetoothLeScanner BTScanner;
39 |
40 | private BluetoothDevice BTDevice;
41 | private BluetoothGatt BLEGatt;
42 |
43 | private int CurrentState = BluetoothProfile.STATE_DISCONNECTED;
44 |
45 | private int GattStatus = -1;
46 |
47 | private final int GattStatus_LossPower = 8; // not defined in GattStatus
48 |
49 | protected BluetoothGattCharacteristic J1939DataCharacteristic;
50 | protected BluetoothGattCharacteristic J1708DataCharacteristic;
51 |
52 | protected BluetoothGattCharacteristic ClientPacket1Characteristic;
53 | protected BluetoothGattCharacteristic ClientPacket2Characteristic;
54 | protected BluetoothGattCharacteristic ClientPacket3Characteristic;
55 |
56 | private BluetoothGattCharacteristic ClientCharacteristic;
57 |
58 | private BluetoothGattService GenericAccess;
59 | private BluetoothGattService GenericAttribute;
60 |
61 | private BluetoothGattService AdapterService;
62 | private BluetoothGattService ClientService;
63 |
64 | private ArrayList IsCharacteristicNotification = new ArrayList();
65 |
66 | protected boolean IsWritingData;
67 | private int WriteTimeout;
68 | private int WriteTimeoutMax = Const.OneSecond;
69 |
70 | protected boolean IsUpdatingDescriptor;
71 | private int UpdateDescriptorTimeout;
72 | private final int UpdateDescriptorTimeoutMax = 500; // ms
73 |
74 | private Timer NotificationsTimer;
75 | protected final int NotificationsInterval = 100; // ms
76 |
77 | // BLE Scanning
78 |
79 | protected boolean IsScanning;
80 |
81 | protected boolean IsWaitingForAdapter;
82 | protected boolean IsAdapterConnected;
83 |
84 | private final int NoSignal = -128;
85 | private int RawSignalStrength = NoSignal;
86 |
87 | private List DeviceAddresses = new ArrayList();
88 |
89 | private boolean IsAdvertisementTimedOut;
90 |
91 | private Timer AdvertisementTimer;
92 | private Timer DiscoveryTimer;
93 |
94 | private boolean WaitForDisconnect;
95 | private DisconnectThreading DisconnectThread;
96 |
97 | //endregion
98 |
99 | //region Constructor
100 |
101 | public CommBLE(Context context, Handler connectionHandler, BlueFire blueFire)
102 | {
103 | super(context, connectionHandler, blueFire);
104 |
105 | BFDeviceName = BFCommBLE.AdapterName;
106 | }
107 |
108 | //endregion
109 |
110 | //region Initialize
111 |
112 | @Override
113 | protected void Initialize()
114 | {
115 | super.Initialize();
116 |
117 | IsScanning = false;
118 | IsAdapterConnected = false;
119 | }
120 |
121 | //endregion
122 |
123 | //region Connection
124 |
125 | @Override
126 | protected boolean StartConnection()
127 | {
128 | if (!super.StartConnection())
129 | return false;
130 |
131 | try
132 | {
133 | // Check for the ConnectToLastAdapter set by the app
134 | if (IsLastConnectedAdapterSet())
135 | {
136 | if (GetRemoteDevice(blueFire.AdapterId()))
137 | {
138 | AdapterConnected("last/secured", blueFire.AdapterId());
139 | return true;
140 | }
141 | // Did not find last connected adapter.
142 | // Note, it is possible to not find the last connected adapter even though it is plugged in
143 | // so we have to allow for this and drop into the scan.
144 | RaiseNotification("CommBLE", "Failed to find or connect to last/secured adapter '" + blueFire.AdapterId() + "'");
145 | }
146 | else // Check for a previous adapter
147 | {
148 | if (!PreviousId.equals(""))
149 | {
150 | if (GetRemoteDevice(PreviousId))
151 | {
152 | AdapterConnected("previous", PreviousId);
153 | return true;
154 | }
155 | RaiseNotification("CommBLE", "Failed to find or connect to previous adapter '" + PreviousId + "'. Scanning for new adapter." + GetConnectionData());
156 | }
157 | }
158 |
159 | // Did not find an adapter, re-initialize the connection for scanning
160 | if (!InitializeConnection())
161 | return false;
162 |
163 | // Scan for an adapter
164 | if (!ScanForDevice())
165 | {
166 | RaiseNotification("CommBLE", "Failed to find an adapter." + GetConnectionData());
167 | return false;
168 | }
169 |
170 | // Found an adapter, attempt to connect to it
171 | StartDiscoveryTimer();
172 |
173 | if (!ConnectGatt(BTDevice))
174 | return false;
175 |
176 | if (WaitForConnection()) // this will block
177 | {
178 | AdapterConnected("scanned", DeviceAddress);
179 | return true;
180 | }
181 | else
182 | {
183 | RaiseNotification("CommBLE", "Failed to connect to scanned adapter '" + DeviceAddress + "'" + GetConnectionData());
184 | return false;
185 | }
186 |
187 | } catch (Exception ex)
188 | {
189 | RaiseSystemError("CommBLE.StartConnection", ex);
190 | return false;
191 | }
192 | }
193 |
194 | private String GetConnectionData()
195 | {
196 | return (Const.CrLf + "ConnectToLastAdapter=" + blueFire.ConnectToLastAdapter() + ", SecureAdapter=" + blueFire.SecureAdapter() + ", AdapterId='" + blueFire.AdapterId() + "'" + ", ConnectionState=" + this.ConnectionState + ", GattStatus=" + GattStatus);
197 | }
198 |
199 | private boolean GetRemoteDevice(String AdapterId)
200 | {
201 | // Attempt to connect directly to the adapter without scanning
202 | BTDevice = BTAdapter.getRemoteDevice(AdapterId);
203 |
204 | // Check if did not find an adapter.
205 | // Note, it is possible to not find an adapter even though it is plugged in
206 | // and the adapter id is correct.
207 | if (BTDevice.getName() == null)
208 | return false;
209 |
210 | // Found a device (real or cached)
211 | // Note, if the mobile device has previously connected to an adapter it will
212 | // be cached and the device returned even if it's not present.
213 | DeviceName = BTDevice.getName();
214 | DeviceAddress = BTDevice.getAddress();
215 |
216 | // Attempt to connect to it.
217 | StartDiscoveryTimer();
218 |
219 | if (!ConnectGatt(BTDevice))
220 | return false;
221 |
222 | if (WaitForConnection()) // this will block
223 | return true;
224 |
225 | // Failed to connect.
226 | // Note, the discovery timer will disconnect Gatt.
227 | return false;
228 | }
229 |
230 | //endregion
231 |
232 | //region Discovery
233 |
234 | private void StartDiscoveryTimer()
235 | {
236 | // Note, do not set the State to Discovering because BLE doesn't really doesn't have a discovery,
237 | // we just use this for a connection timeout.
238 | // UpdateState(ConnectionStates.Discovering);
239 |
240 | DiscoveryTimer = new Timer();
241 | DiscoveryTimer.schedule(new DiscoveryTimedOut(), blueFire.DiscoveryTimeout(), Long.MAX_VALUE);
242 | }
243 |
244 | private class DiscoveryTimedOut extends TimerTask
245 | {
246 | @Override
247 | public void run()
248 | {
249 | try
250 | {
251 | // Stop the discovery timer (but don't nuke it)
252 | DiscoveryTimer.cancel();
253 |
254 | // Check if still scanning.
255 | // Note, if an adapter is found the scan will be stopped
256 | if (IsScanning)
257 | StopScan();
258 |
259 | Disconnect();
260 |
261 | AdapterNotConnected();
262 |
263 | } catch (Exception ex)
264 | {
265 | }
266 | }
267 | };
268 |
269 | private void StopDiscoveryTimer()
270 | {
271 | try
272 | {
273 | if (DiscoveryTimer != null)
274 | {
275 | DiscoveryTimer.cancel();
276 | DiscoveryTimer.purge();
277 | DiscoveryTimer = null;
278 | }
279 | }
280 | catch(Exception ex){}
281 | }
282 |
283 | //endregion
284 |
285 | //region Scanning
286 |
287 | private boolean ScanForDevice()
288 | {
289 | StartScan();
290 |
291 | WaitForAdapter();
292 |
293 | StopScan();
294 |
295 | if (DeviceName == "")
296 | return false;
297 |
298 | // Check for not last adapter id
299 | if (!IsValidAdapter())
300 | return false;
301 |
302 | return true;
303 | }
304 |
305 | public boolean WaitForAdapter()
306 | {
307 | while (IsWaitingForAdapter && !IsAdvertisementTimedOut)
308 | Helper.Sleep(10);
309 |
310 | StopAdvertisementTimer();
311 |
312 | return !IsAdvertisementTimedOut;
313 | }
314 |
315 | protected boolean WaitForConnection()
316 | {
317 | while (!IsAdapterConnected && (ConnectionState == ConnectionStates.Connecting ||ConnectionState == ConnectionStates.Reconnecting))
318 | Helper.Sleep(100);
319 |
320 | StopDiscoveryTimer();
321 |
322 | return IsAdapterConnected;
323 | }
324 |
325 | // Method to scan BLE Devices. The status of the scan will be detected in the BluetoothAdapter.LeScanCallback
326 | private void StartScan()
327 | {
328 | try
329 | {
330 | IsScanning = true;
331 |
332 | RawSignalStrength = NoSignal;
333 |
334 | DeviceName = "";
335 | DeviceAddress = "";
336 | DeviceAddresses.clear();
337 |
338 | StartAdvertisementTimer(blueFire.AdvertisementTimeout());
339 |
340 | if (BTScanner == null)
341 | BTScanner = BTAdapter.getBluetoothLeScanner();
342 |
343 | Builder SettingsBuilder = new Builder();
344 | SettingsBuilder.setCallbackType(CALLBACK_TYPE_ALL_MATCHES);
345 | SettingsBuilder.setScanMode(SCAN_MODE_BALANCED);
346 | ScanSettings Settings = SettingsBuilder.build();
347 |
348 | List Filters = new ArrayList();
349 | ScanFilter.Builder FilterBuilder = new ScanFilter.Builder();
350 | FilterBuilder.setDeviceName(BFCommBLE.AdapterName);
351 | ScanFilter Filter = FilterBuilder.build();
352 | Filters.add(Filter);
353 |
354 | BTScanner.startScan(Filters, Settings, BLEScanCallback);
355 |
356 | } catch (Exception ex)
357 | {
358 | IsScanning = false;
359 | RaiseSystemError("CommBLE StartScan", ex);
360 | }
361 | }
362 |
363 | private void StopScan()
364 | {
365 | try
366 | {
367 | if (!IsScanning)
368 | return;
369 |
370 | IsScanning = false;
371 |
372 | StopAdvertisementTimer();
373 |
374 | if (!BTAdapter.isEnabled())
375 | return;
376 |
377 | if (BTScanner != null)
378 | BTScanner.stopScan(BLEScanCallback);
379 |
380 | } catch (Exception ex)
381 | {
382 | RaiseSystemError("CommBLE StopScan", ex);
383 | }
384 | }
385 |
386 | private ScanCallback BLEScanCallback = new ScanCallback()
387 | {
388 | // Call back for BLE Scan.
389 | // This call back is called when a BLE device is found near by.
390 |
391 | @Override
392 | public void onScanResult(int CallbackType, ScanResult Result)
393 | {
394 | try
395 | {
396 | // Ignore if scanning has been stopped
397 | if (!IsScanning)
398 | return;
399 |
400 | if (!IsWaitingForAdapter)
401 | return;
402 |
403 | BluetoothDevice AdDevice = Result.getDevice();
404 |
405 | String AdDeviceName = AdDevice.getName() + ""; // in case it is null;
406 | String AdDeviceAddress = AdDevice.getAddress();
407 | int AdSignalStrength = Result.getRssi();
408 |
409 | // Ignore duplicate adapter events
410 | if (DeviceAddresses.contains(AdDeviceAddress))
411 | return;
412 | else
413 | DeviceAddresses.add(AdDeviceAddress);
414 |
415 | // Ignore if not a valid BlueFire adapter.
416 | // Note, this will check for a BlueFire adapter that is the correct adapter
417 | // if the last connected adapter is set, or a any BlueFire adapter.
418 | if (!IsValidAdapter(AdDeviceName, AdDeviceAddress))
419 | return;
420 |
421 | // Check for finding a last connected adapter
422 | if (IsLastConnectedAdapter(AdDeviceAddress))
423 | {
424 | BTDevice = AdDevice;
425 | DeviceName = AdDeviceName;
426 | DeviceAddress = AdDeviceAddress;
427 | IsWaitingForAdapter = false;
428 | return;
429 | }
430 |
431 | // Keep looking for an adapter with the best signal.
432 | // Note, this will continue until the WaitingForAdapter times out.
433 | if (AdSignalStrength > RawSignalStrength)
434 | {
435 | BTDevice = AdDevice;
436 | DeviceName = AdDeviceName;
437 | DeviceAddress = AdDeviceAddress;
438 | RawSignalStrength = AdSignalStrength;
439 | }
440 |
441 | // Keep waiting for another adapter
442 | StartAdvertisementTimer(Const.OneSecond);
443 |
444 | } catch (Exception ex)
445 | {
446 | RaiseSystemError("CommBLE OnLeScan", ex);
447 | }
448 | }
449 |
450 | @Override
451 | public void onScanFailed(int ErrorCode)
452 | {
453 | RaiseSystemError("CommBLE onScanFailed","BLEScanCallback Failed, ErrorCode=" + ErrorCode);
454 | }
455 | };
456 |
457 | //endregion
458 |
459 | //region Advertising
460 |
461 | private void StartAdvertisementTimer(int TimeoutInterval)
462 | {
463 | IsWaitingForAdapter = true;
464 | IsAdvertisementTimedOut = false;
465 |
466 | AdvertisementTimer = new Timer();
467 | AdvertisementTimer.schedule(new AdvertisementTimedOut(), TimeoutInterval, Long.MAX_VALUE);
468 | }
469 |
470 | private void StopAdvertisementTimer()
471 | {
472 | IsWaitingForAdapter = false;
473 | try
474 | {
475 | if (AdvertisementTimer != null)
476 | {
477 | AdvertisementTimer.cancel();
478 | AdvertisementTimer.purge();
479 | AdvertisementTimer = null;
480 | }
481 | }
482 | catch(Exception ex){}
483 | }
484 |
485 | private class AdvertisementTimedOut extends TimerTask
486 | {
487 | @Override
488 | public void run()
489 | {
490 | try
491 | {
492 | // Stop the discovery timer (but don't nuke it)
493 | StopAdvertisementTimer();
494 | //AdvertisementTimer.cancel();
495 |
496 | IsAdvertisementTimedOut = true;
497 |
498 | if (IsScanning)
499 | StopScan();
500 |
501 | } catch (Exception ex)
502 | {
503 | }
504 | }
505 | };
506 |
507 | //endregion
508 |
509 | //region GATT Connection
510 |
511 | protected boolean ConnectGatt(BluetoothDevice Device)
512 | {
513 | try
514 | {
515 | // Get the connection status of the device
516 | if (CurrentState != BluetoothProfile.STATE_DISCONNECTED)
517 | DisconnectGatt();
518 |
519 | CurrentState = BluetoothProfile.STATE_DISCONNECTED;
520 |
521 | // android.util.Log.d("BlueFire", "CommBLE ConnectGatt, Connecting Gatt");
522 |
523 | BLEGatt = Device.connectGatt(Context, true, BLEGattCallback);
524 |
525 | return true;
526 |
527 | } catch (Exception ex)
528 | {
529 | if (ex.getMessage().contains("null object reference"))
530 | return false;
531 |
532 | RaiseSystemError("CommBLE ConnectGatt", ex);
533 | return false;
534 | }
535 | }
536 |
537 | //endregion
538 |
539 | //region GATT Callback
540 |
541 | private BluetoothGattCallback BLEGattCallback = new BluetoothGattCallback()
542 | {
543 | // Check if the adapter connection changed (eg. connected)
544 | @Override
545 | public void onConnectionStateChange(BluetoothGatt Gatt, int Status, int NewState)
546 | {
547 | if (Gatt == null || BLEGatt == null)
548 | return;
549 |
550 | GattStatus = Status;
551 |
552 | try
553 | {
554 | switch (Status)
555 | {
556 | case BluetoothGatt.GATT_FAILURE:
557 | case BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION:
558 | case BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION:
559 | case BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH:
560 | case BluetoothGatt.GATT_INVALID_OFFSET:
561 | case BluetoothGatt.GATT_READ_NOT_PERMITTED:
562 | case BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED:
563 | case BluetoothGatt.GATT_WRITE_NOT_PERMITTED:
564 | StopScan();
565 | RaiseDataError("CommBLE onConnectionStateChange, Gatt Status=" + Status);
566 | return;
567 | case 61:
568 | StopScan();
569 | RaiseDataError("CommBLE onConnectionStateChange, Gatt Status=" + Status);
570 | return;
571 | }
572 |
573 | if (NewState == CurrentState) // no change
574 | return;
575 |
576 | CurrentState = NewState;
577 |
578 | // android.util.Log.d("BlueFire", "CommBLE BLEGattCallback, New State=" + NewState + ", Current State=" + CurrentState);
579 |
580 | switch (NewState)
581 | {
582 | case BluetoothProfile.STATE_CONNECTING:
583 | break;
584 |
585 | case BluetoothProfile.STATE_CONNECTED:
586 | StopScan();
587 |
588 | if (IsConnecting)
589 | BLEGatt.discoverServices();
590 | break;
591 |
592 | case BluetoothProfile.STATE_DISCONNECTING:
593 | if (IsConnecting || IsConnected)
594 | AdapterNotConnected();
595 | break;
596 |
597 | case BluetoothProfile.STATE_DISCONNECTED:
598 | // android.util.Log.d("BlueFire", "CommBLE BLEGattCallback, Gatt Disconnected, closing Gatt, State=" + NewState + ", Current State=" + CurrentState);
599 |
600 | // Close the Gatt connection.
601 | // Note, this must be before AdapterNotConnected.
602 | CloseGatt(false);
603 |
604 | // Check for notifying the app
605 | if (IsConnecting || IsConnected)
606 | AdapterNotConnected();
607 | break;
608 | }
609 | } catch (Exception ex)
610 | {
611 | RaiseSystemError("CommBLE OnConnectionStateChange", ex);
612 | }
613 | }
614 |
615 | // Check for discovering the adapter
616 | @Override
617 | public void onServicesDiscovered(BluetoothGatt Gatt, int Status)
618 | {
619 | if (Status != BluetoothGatt.GATT_SUCCESS)
620 | {
621 | RaiseDataError("CommBLE OnServicesDiscovered, Gatt Status=" + Status);
622 | return;
623 | }
624 |
625 | // Get the Gatt services and characteristics
626 | AdapterService = null;
627 | ClientService = null;
628 |
629 | GetGattServices();
630 | }
631 |
632 | @Override
633 | public void onCharacteristicChanged(BluetoothGatt Gatt, BluetoothGattCharacteristic Characteristic)
634 | {
635 | // GATT Characteristic data changed
636 | String UUID = Characteristic.getUuid().toString().toUpperCase();
637 |
638 | //Helper.DebugPrint("CommBLE OnCharacteristicChanged - UUID=" + UUID);
639 |
640 | if (UUID.equals(BFCommBLE.J1939DataCharacteristicUUID) ||
641 | UUID.equals(BFCommBLE.J1708DataCharacteristicUUID) ||
642 | UUID.equals(BFCommBLE.ClientPacket1CharacteristicUUID) ||
643 | UUID.equals(BFCommBLE.ClientPacket2CharacteristicUUID) ||
644 | UUID.equals(BFCommBLE.ClientPacket3CharacteristicUUID))
645 | // Characteristic data changed, queue it for processing
646 | ReceiveAdapterData(Characteristic.getValue());
647 | }
648 |
649 | @Override
650 | public void onCharacteristicWrite(BluetoothGatt Gatt, BluetoothGattCharacteristic Characteristic, int Status)
651 | {
652 | IsWritingData = false;
653 |
654 | //Helper.DebugPrint("onCharacteristicWrite - IsWritingData="+IsWritingData);
655 | }
656 |
657 | @Override
658 | public void onDescriptorWrite(BluetoothGatt Gatt, BluetoothGattDescriptor Descriptor, int Status)
659 | {
660 | // Helper.DebugPrint("CommBLE OnDescriptorWrite - Descriptor=" + Descriptor.Characteristic.Uuid.ToString().ToUpper() + ", Status=" + Status.ToString());
661 |
662 | IsUpdatingDescriptor = false;
663 | }
664 | };
665 |
666 | //endregion
667 |
668 | //region GATT Services
669 |
670 | private void GetGattServices()
671 | {
672 | try
673 | {
674 | List GattServices = (List) BLEGatt.getServices();
675 |
676 | if (GattServices == null)
677 | return;
678 |
679 | // Loops through available GATT Services.
680 | for (BluetoothGattService GattService : GattServices)
681 | {
682 | String UUID = GattService.getUuid().toString().toUpperCase();
683 |
684 | if (UUID.equals(BFCommBLE.GenericAccessServiceUUID))
685 | GenericAccess = GattService;
686 |
687 | else if (UUID.equals(BFCommBLE.GenericAttributeServiceUUID))
688 | GenericAttribute = GattService;
689 |
690 | else if (UUID.equals(BFCommBLE.AdapterServiceUUID))
691 | {
692 | AdapterService = GattService;
693 |
694 | for (int i = 0; i < AdapterService.getCharacteristics().size(); i++) // count should be 2
695 | {
696 | BluetoothGattCharacteristic ServiceCharacteristic = AdapterService.getCharacteristics().get(i);
697 | String AdapterCharacteristicValue = ServiceCharacteristic.getUuid().toString().toUpperCase();
698 |
699 | if (AdapterCharacteristicValue.equals(BFCommBLE.J1939DataCharacteristicUUID))
700 | J1939DataCharacteristic = ServiceCharacteristic;
701 |
702 | else if (AdapterCharacteristicValue.equals(BFCommBLE.J1708DataCharacteristicUUID))
703 | J1708DataCharacteristic = ServiceCharacteristic;
704 | }
705 | }
706 |
707 | else if (UUID.equals(BFCommBLE.ClientServiceUUID))
708 | {
709 | ClientService = GattService;
710 |
711 | for (int i = 0; i < ClientService.getCharacteristics().size(); i++) // count should be 3
712 | {
713 | BluetoothGattCharacteristic ServiceCharacteristic = ClientService.getCharacteristics().get(i);
714 | String AdapterCharacteristicValue = ServiceCharacteristic.getUuid().toString().toUpperCase();
715 |
716 | if (AdapterCharacteristicValue.equals(BFCommBLE.ClientPacket1CharacteristicUUID))
717 | ClientPacket1Characteristic = ServiceCharacteristic;
718 |
719 | else if (AdapterCharacteristicValue.equals(BFCommBLE.ClientPacket2CharacteristicUUID))
720 | ClientPacket2Characteristic = ServiceCharacteristic;
721 |
722 | else if (AdapterCharacteristicValue.equals(BFCommBLE.ClientPacket3CharacteristicUUID))
723 | ClientPacket3Characteristic = ServiceCharacteristic;
724 | }
725 | }
726 | }
727 |
728 | if (AdapterService == null || ClientService == null)
729 | {
730 | String Message = "";
731 |
732 | if (AdapterService == null && ClientService == null)
733 | Message = "BlueFire and Client Services.";
734 |
735 | else if (AdapterService == null)
736 | Message = "BlueFire Service.";
737 |
738 | else if (ClientService == null)
739 | Message += "Client Service.";
740 |
741 | RaiseDataError("CommBLE GetGattServices, Failed to Discover " + Message);
742 | return;
743 | }
744 |
745 | // All characteristics have been discovered, enable notifications
746 | StartNotifications();
747 | } catch (Exception ex)
748 | {
749 | RaiseSystemError("CommBLE GetGattServices", ex);
750 | }
751 | }
752 |
753 | //endregion
754 |
755 | //region GATT Notifications
756 |
757 | protected void StartNotifications()
758 | {
759 | // Must start notifications from a timer to execute outside of Gatt event
760 | NotificationsTimer = new Timer();
761 | NotificationsTimer.schedule(new NotificationsTimedOut(), NotificationsInterval, NotificationsInterval);
762 | }
763 |
764 | // This is a one time shot
765 | private class NotificationsTimedOut extends TimerTask
766 | {
767 | @Override
768 | public void run()
769 | {
770 | StopNotificationsTimer();
771 |
772 | if (StartAllNotifications())
773 | // All characteristics notifications have been enabled, adapter is connected
774 | IsAdapterConnected = true;
775 | }
776 | };
777 |
778 | private void StopNotificationsTimer()
779 | {
780 | try
781 | {
782 | if (NotificationsTimer != null)
783 | {
784 | NotificationsTimer.cancel();
785 | NotificationsTimer.purge();
786 | NotificationsTimer = null;
787 | }
788 | }
789 | catch(Exception ex){}
790 | }
791 |
792 | private boolean StartAllNotifications()
793 | {
794 | IsCharacteristicNotification.clear();
795 |
796 | if (!StartStopNotifications(AdapterService, true))
797 | return false;
798 |
799 | if (!StartStopNotifications(ClientService, true))
800 | return false;
801 |
802 | return true;
803 | }
804 |
805 | private boolean StopNotifications()
806 | {
807 | if (!StartStopNotifications(AdapterService, false))
808 | return false;
809 |
810 | if (!StartStopNotifications(ClientService, false))
811 | return false;
812 |
813 | return true;
814 | }
815 |
816 | protected boolean StartAdapterNotifications()
817 | {
818 | return StartStopNotifications(AdapterService, true);
819 | }
820 |
821 | protected boolean StopAdapterNotifications()
822 | {
823 | return StartStopNotifications(AdapterService, false);
824 | }
825 |
826 | private boolean StartStopNotifications(BluetoothGattService Service, boolean Start)
827 | {
828 | try
829 | {
830 | // if (BTDevice == null || BLEGatt == null || Service == null || Service.getCharacteristics() == null)
831 | // return false;
832 |
833 | if (CurrentState != BluetoothProfile.STATE_CONNECTED)
834 | return false;
835 |
836 | int CharacteristicsCount = Service.getCharacteristics().size();
837 |
838 | for (int i = 0; i < CharacteristicsCount; i++)
839 | {
840 | // if (Service == null)
841 | // return false;
842 |
843 | BluetoothGattCharacteristic ServiceCharacteristic = Service.getCharacteristics().get(i);
844 |
845 | // if (Service == null || Service.getCharacteristics() == null || ServiceCharacteristic == null)
846 | // return false;
847 |
848 | if (Start)
849 | {
850 | if (!StartNotification(ServiceCharacteristic))
851 | return false;
852 | }
853 | else
854 | {
855 | if (!StopNotification(ServiceCharacteristic))
856 | return false;
857 | }
858 |
859 | WaitForDescriptorUpdate();
860 | }
861 |
862 | return true;
863 |
864 | } catch (Exception ex)
865 | {
866 | if (ex.getMessage().contains("null object reference"))
867 | return false;
868 |
869 | RaiseSystemError("CommBLE StartStopNotifications - Start=" + Start, ex);
870 | return false;
871 | }
872 | }
873 |
874 | protected boolean StartNotification(BluetoothGattCharacteristic ServiceCharacteristic)
875 | {
876 | try
877 | {
878 | // if (BTDevice == null || BLEGatt == null || ServiceCharacteristic == null)
879 | // return false;
880 |
881 | String CharacteristicUUID = ServiceCharacteristic.getUuid().toString().toUpperCase();
882 |
883 | IsCharacteristicNotification.remove(CharacteristicUUID);
884 |
885 | // if (BLEGatt == null || ServiceCharacteristic == null)
886 | // return false;
887 |
888 | BLEGatt.setCharacteristicNotification(ServiceCharacteristic, true);
889 |
890 | // if (BLEGatt == null || ServiceCharacteristic == null)
891 | // return false;
892 |
893 | BluetoothGattDescriptor Descriptor = ServiceCharacteristic.getDescriptor(UUID.fromString(BFCommBLE.ClientCharacteristicConfigUUID));
894 |
895 | // if (Descriptor == null)
896 | // return false;
897 |
898 | Descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
899 |
900 | // if (BLEGatt == null)
901 | // return false;
902 |
903 | BLEGatt.writeDescriptor(Descriptor);
904 |
905 | IsCharacteristicNotification.add(CharacteristicUUID);
906 |
907 | return true;
908 |
909 | } catch (Exception ex)
910 | {
911 | if (ex.getMessage().contains("null object reference"))
912 | return false;
913 |
914 | RaiseSystemError("CommBLE.StartNotification", ex);
915 | return false;
916 | }
917 | }
918 |
919 | private boolean StopNotification(BluetoothGattCharacteristic ServiceCharacteristic)
920 | {
921 | try
922 | {
923 | // if (BTDevice == null || BLEGatt == null || ServiceCharacteristic == null)
924 | // return false;
925 |
926 | String CharacteristicUUID = ServiceCharacteristic.getUuid().toString().toUpperCase();
927 |
928 | if (!IsCharacteristicNotification.contains(CharacteristicUUID))
929 | return false;
930 |
931 | // if (BLEGatt == null || ServiceCharacteristic == null)
932 | // return false;
933 |
934 | BLEGatt.setCharacteristicNotification(ServiceCharacteristic, false);
935 |
936 | // if (BLEGatt == null || ServiceCharacteristic == null)
937 | // return false;
938 |
939 | BluetoothGattDescriptor Descriptor = ServiceCharacteristic.getDescriptor(UUID.fromString(BFCommBLE.ClientCharacteristicConfigUUID));
940 |
941 | // if (Descriptor == null)
942 | // return false;
943 |
944 | Descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
945 |
946 | // if (BLEGatt == null)
947 | // return false;
948 |
949 | BLEGatt.writeDescriptor(Descriptor);
950 |
951 | IsCharacteristicNotification.remove(CharacteristicUUID);
952 |
953 | return true;
954 |
955 | } catch (Exception ex)
956 | {
957 | if (ex.getMessage().contains("null object reference"))
958 | return false;
959 |
960 | RaiseSystemError("CommBLE.StopNotification", ex);
961 | return false;
962 | }
963 | }
964 |
965 | private void WaitForDescriptorUpdate()
966 | {
967 | IsUpdatingDescriptor = true;
968 |
969 | UpdateDescriptorTimeout = 0;
970 | while (IsUpdatingDescriptor && UpdateDescriptorTimeout < UpdateDescriptorTimeoutMax)
971 | {
972 | Helper.Sleep(10);
973 | UpdateDescriptorTimeout += 10;
974 | }
975 | }
976 |
977 | //endregion
978 |
979 | //region GATT Disconnection
980 |
981 | private boolean IsClosingGatt;
982 | private boolean IsDisconnectingGatt;
983 |
984 | private void DisconnectGatt()
985 | {
986 | try
987 | {
988 | if (BLEGatt == null)
989 | return;
990 |
991 | if (IsDisconnectingGatt)
992 | return;
993 |
994 | if (IsClosingGatt)
995 | return;
996 |
997 | IsDisconnectingGatt = true;
998 |
999 | // Disconnect the Gatt connection.
1000 | // android.util.Log.d("BlueFire", "CommBLE DisconnectGatt, Disconnecting Gatt");
1001 | BLEGatt.disconnect();
1002 |
1003 | // Must give Bluetooth time to close the Gatt connection or be reconnected.
1004 | // Note, the Gatt connection is closed in the callback.
1005 | int Timeout = blueFire.BleDisconnectWaitTime();
1006 | while (true)
1007 | {
1008 | // Check if Gatt has been closed
1009 | if (BLEGatt == null)
1010 | break;
1011 |
1012 | // Check if Gatt has been reconnected
1013 | if (CurrentState == BluetoothProfile.STATE_CONNECTED)
1014 | break;
1015 |
1016 | // Check for timeout waiting for Gatt to close or be reconnected
1017 | if (Timeout <= 0)
1018 | {
1019 | // android.util.Log.d("BlueFire", "CommBLE DisconnectGatt, Timeout waiting for GATT to close, State=" + CurrentState);
1020 | CloseGatt(true);
1021 | break;
1022 | }
1023 | Helper.Sleep(100);
1024 | Timeout-= 100;
1025 | }
1026 |
1027 | IsDisconnectingGatt = false;
1028 |
1029 | } catch (Exception ex)
1030 | {
1031 | RaiseSystemError("CommBLE DisconnectGatt", ex);
1032 |
1033 | IsDisconnectingGatt = false;
1034 | }
1035 | }
1036 |
1037 | private void CloseGatt(boolean WaitForClose)
1038 | {
1039 | try
1040 | {
1041 | if (BLEGatt == null)
1042 | return;
1043 |
1044 | if (IsClosingGatt)
1045 | return;
1046 |
1047 | IsClosingGatt = true;
1048 |
1049 | // Close the Gatt connection.
1050 | // android.util.Log.d("BlueFire", "CommBLE CloseGatt, Closing Gatt, WaitForClose=" + WaitForClose);
1051 | BLEGatt.close();
1052 |
1053 | // Give Bluetooth time to fully close the Gatt connection
1054 | if (WaitForClose)
1055 | Helper.Sleep(blueFire.BleDisconnectWaitTime());
1056 |
1057 | BLEGatt = null; // not a good idea in case the wait time is not enough
1058 |
1059 | } catch (Exception ex)
1060 | {
1061 | RaiseSystemError("CommBLE CloseGatt", ex);
1062 | }
1063 |
1064 | IsClosingGatt = false;
1065 | }
1066 |
1067 | //endregion
1068 |
1069 | //region Adapter Connected
1070 |
1071 | @Override
1072 | protected void AdapterConnected()
1073 | {
1074 | StopDiscoveryTimer();
1075 |
1076 | super.AdapterConnected();
1077 | }
1078 |
1079 | private void AdapterConnected(String Text, String DeviceAddress)
1080 | {
1081 | RaiseNotification("CommBLE", "Connected to " + Text + " adapter '" + DeviceAddress + "'");
1082 |
1083 | AdapterConnected();
1084 | }
1085 |
1086 | @Override
1087 | protected void AdapterNotConnected()
1088 | {
1089 | try
1090 | {
1091 | super.AdapterNotConnected();
1092 |
1093 | } catch (Exception ex)
1094 | {
1095 | }
1096 | }
1097 |
1098 | //endregion
1099 |
1100 | //region Send Adapter Data
1101 |
1102 | @Override
1103 | protected boolean SendAdapterData(byte[] DataBuffer, int DataLength)
1104 | {
1105 | try
1106 | {
1107 | if (!IsAdapterConnected)
1108 | return false;
1109 |
1110 | super.SendAdapterData(DataBuffer, DataLength);
1111 |
1112 | byte PacketNo;
1113 | int PacketLength;
1114 |
1115 | if (DataLength <= BFCommBLE.ClientPacket1Length)
1116 | {
1117 | PacketNo = BFCommBLE.ClientPacket1;
1118 | PacketLength = BFCommBLE.ClientPacket1Length;
1119 | }
1120 | else if (DataLength <= BFCommBLE.ClientPacket2Length)
1121 | {
1122 | PacketNo = BFCommBLE.ClientPacket2;
1123 | PacketLength = BFCommBLE.ClientPacket2Length;
1124 | }
1125 | else if (DataLength <= BFCommBLE.ClientPacket3Length)
1126 | {
1127 | PacketNo = BFCommBLE.ClientPacket3;
1128 | PacketLength = BFCommBLE.ClientPacket3Length;
1129 | }
1130 | else
1131 | {
1132 | RaiseSystemError("CommBLE.SendClientData", new Exception("Invalid Client Data Length=" + DataLength));
1133 | return false;
1134 | }
1135 |
1136 | // Copy the data allowing room for the packet no.
1137 | byte[] PacketData = new byte[PacketLength + 1]; // add a byte for the Packet No
1138 |
1139 | PacketData[0] = PacketNo;
1140 | System.arraycopy(DataBuffer, 0, PacketData, 1, DataLength);
1141 |
1142 | IsWritingData = true;
1143 |
1144 | // Send the data to the adapter using the correct characteristic
1145 | if (!WriteData(PacketData))
1146 | {
1147 | IsWritingData = false;
1148 | return false;
1149 | }
1150 |
1151 | // Wait for data to be sent
1152 | if (!WaitForWrittenData())
1153 | {
1154 | IsWritingData = false;
1155 | if (IsAdapterConnected && IsConnected)
1156 | RaiseNotification("CommBLE.SendClientData", "BLE Write Timeout");
1157 |
1158 | return false;
1159 | }
1160 |
1161 | IsWritingData = false;
1162 |
1163 | return true;
1164 | }
1165 | catch (Exception ex)
1166 | {
1167 | RaiseSystemError("CommBLE.SendClientData", ex);
1168 | return false;
1169 | }
1170 | }
1171 |
1172 | // Write data to the adapter
1173 | private boolean WriteData(byte[] PacketData)
1174 | {
1175 | try
1176 | {
1177 | // if (BLEGatt == null)
1178 | // return false;
1179 |
1180 | // Send the data to the adapter using the correct characteristic
1181 | switch (PacketData[0])
1182 | {
1183 | case BFCommBLE.ClientPacket1:
1184 | ClientCharacteristic = ClientPacket1Characteristic;
1185 | break;
1186 |
1187 | case BFCommBLE.ClientPacket2:
1188 | ClientCharacteristic = ClientPacket2Characteristic;
1189 | break;
1190 |
1191 | case BFCommBLE.ClientPacket3:
1192 | ClientCharacteristic = ClientPacket3Characteristic;
1193 | break;
1194 |
1195 | default:
1196 | return false;
1197 | }
1198 |
1199 | // if (ClientCharacteristic == null)
1200 | // return false;
1201 |
1202 | ClientCharacteristic.setValue(PacketData);
1203 |
1204 | BLEGatt.writeCharacteristic(ClientCharacteristic);
1205 |
1206 | return true;
1207 | }
1208 | catch (Exception ex)
1209 | {
1210 | if (ex.getMessage().contains("null object reference"))
1211 | return false;
1212 |
1213 | RaiseSystemError("CommBLE.WriteData", ex);
1214 | return false;
1215 | }
1216 | }
1217 |
1218 | private boolean WaitForWrittenData()
1219 | {
1220 | WriteTimeout = 0;
1221 |
1222 | // Wait for data to be written
1223 | while (IsWritingData && IsAdapterConnected && WriteTimeout < WriteTimeoutMax)
1224 | {
1225 | Helper.Sleep(10);
1226 | WriteTimeout += 10;
1227 | }
1228 |
1229 | // Check for a timeout writing data
1230 | if (WriteTimeout >= WriteTimeoutMax)
1231 | return false;
1232 |
1233 | // No timeout
1234 | return true;
1235 | }
1236 |
1237 | //endregion
1238 |
1239 | //region Receive Adapter Data
1240 |
1241 | @Override
1242 | protected void ReceiveAdapterData(byte[] DataBuffer)
1243 | {
1244 | super.ReceiveAdapterData(DataBuffer);
1245 | }
1246 |
1247 | //endregion
1248 |
1249 | //region Disconnect
1250 |
1251 | @Override
1252 | protected boolean Disconnect()
1253 | {
1254 | return Disconnect(false);
1255 | }
1256 |
1257 | @Override
1258 | public boolean Disconnect(boolean WaitForDisconnect)
1259 | {
1260 | // Note, it is critical that Gatt is disconnected because if it is not the
1261 | // adapter will not advertise itself.
1262 |
1263 | try
1264 | {
1265 | if (!super.Disconnect(WaitForDisconnect))
1266 | {
1267 | DisconnectGatt();
1268 | return false;
1269 | }
1270 |
1271 | IsAdapterConnected = false;
1272 |
1273 | if (ConnectionState == ConnectionStates.Disconnecting || this.ConnectionState == ConnectionStates.Disconnected)
1274 | {
1275 | DisconnectGatt();
1276 | return false;
1277 | }
1278 |
1279 | UpdateState(ConnectionStates.Disconnecting);
1280 |
1281 | if (BTAdapter == null)
1282 | {
1283 | DisconnectGatt();
1284 | AdapterNotConnected();
1285 | return false;
1286 | }
1287 |
1288 | // Disconnect Bluetooth
1289 | // Note, this must be done in a thread to allow the Disconnecting state
1290 | // to be processed by the event handlers.
1291 |
1292 | this.WaitForDisconnect = WaitForDisconnect;
1293 | DisconnectThread = new DisconnectThreading();
1294 | DisconnectThread.start();
1295 |
1296 | return true;
1297 |
1298 | } catch (Exception ex)
1299 | {
1300 | DisconnectGatt();
1301 | RaiseSystemError("CommBLE.Disconnect", ex);
1302 | return false;
1303 | }
1304 | }
1305 |
1306 | private class DisconnectThreading extends Thread
1307 | {
1308 | public void run()
1309 | {
1310 | try
1311 | {
1312 | // Stop scanning
1313 | StopScan();
1314 |
1315 | // Stop discovering
1316 | StopDiscoveryTimer();
1317 |
1318 | // Stop adapter sending notifications
1319 | StopNotifications();
1320 |
1321 | ClearInputPackets();
1322 |
1323 | // Disconnect Gatt
1324 | DisconnectGatt();
1325 |
1326 | if (BTDevice != null)
1327 | BTDevice = null;
1328 |
1329 | CheckWaitForDisconnect(WaitForDisconnect);
1330 |
1331 | } catch (Exception ex)
1332 | {
1333 | DisconnectGatt();
1334 | RaiseSystemError("CommBLE.DisconnectThreading", ex);
1335 | }
1336 | }
1337 | }
1338 |
1339 | //endregion
1340 |
1341 | //region Dispose
1342 |
1343 | @Override
1344 | public void Dispose()
1345 | {
1346 | super.Dispose();
1347 | }
1348 |
1349 | //endregion
1350 | }
1351 |
--------------------------------------------------------------------------------
/APIDemo/src/main/java/com/bluefire/apidemo/CommBT2.java:
--------------------------------------------------------------------------------
1 | package com.bluefire.apidemo;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 | import android.bluetooth.BluetoothSocket;
5 | import android.content.BroadcastReceiver;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.IntentFilter;
9 | import android.os.Handler;
10 |
11 | import com.bluefire.api.BFCommBT2;
12 | import com.bluefire.api.BlueFire;
13 | import com.bluefire.api.ConnectionStates;
14 | import com.bluefire.api.Helper;
15 |
16 | import java.io.IOException;
17 | import java.io.InputStream;
18 | import java.io.OutputStream;
19 | import java.util.Set;
20 | import java.util.Timer;
21 | import java.util.TimerTask;
22 |
23 | public class CommBT2 extends Comm
24 | {
25 | //region Declaratives
26 |
27 | private BluetoothSocket Socket = null;
28 |
29 | private InputStream InStream = null;
30 | private OutputStream OutStream = null;
31 |
32 | private boolean BTpairing = false;
33 | private boolean BTreceiving = false;
34 | private boolean BTpairingError = false;
35 | private boolean BTfoundDevice = false;
36 | private boolean BTreceiverUnregistered = false;
37 |
38 | private Timer DiscoveryTimer;
39 |
40 | // Get Data
41 |
42 | private int DataByte;
43 | private int BufferIndex;
44 | private byte[] StreamBuffer = new byte[BFCommBT2.MaxMessageSize]; // length bytes + max message data + checksum
45 |
46 | private int DataLength;
47 | private int MessageLength;
48 |
49 | //endregion
50 |
51 | //region Constructor
52 |
53 | public CommBT2(Context context, Handler connectionHandler, BlueFire blueFire)
54 | {
55 | super(context, connectionHandler, blueFire);
56 |
57 | BFDeviceName = BFCommBT2.AdapterName;
58 | }
59 |
60 | //endregion
61 |
62 | //region Initialize
63 |
64 | @Override
65 | protected void Initialize()
66 | {
67 | super.Initialize();
68 |
69 | BTpairing = false;
70 | BTreceiving = false;
71 | BTfoundDevice = false;
72 | BTpairingError = false;
73 | BTreceiverUnregistered = false;
74 |
75 | BTreceiving = true; // ignore discovery timeout
76 | }
77 |
78 | //endregion
79 |
80 | //region Connection
81 |
82 | @Override
83 | protected boolean StartConnection()
84 | {
85 | if (!super.StartConnection())
86 | return false;
87 |
88 | try
89 | {
90 | // Check for a paired last connected device
91 | if (IsLastConnectedDevice())
92 | return true;
93 |
94 | // Check for not finding a last connected device
95 | if (IsLastConnectedAdapterSet())
96 | return false;
97 |
98 | // Check for a paired BlueFire device
99 | if (IsBlueFireDevice())
100 | return true;
101 |
102 | // Last device is not connected, start the discovery process.
103 | // Note, this is faster than trying to connect to each paired device.
104 | if (ConnectionState == ConnectionStates.Connecting || ConnectionState == ConnectionStates.Reconnecting)
105 | StartDiscovery();
106 |
107 | return true;
108 |
109 | } catch (Exception ex)
110 | {
111 | RaiseSystemError ("CommBT2.StartConnection", ex);
112 | return false;
113 | }
114 | }
115 |
116 | private Boolean IsLastConnectedDevice()
117 | {
118 | // Get all paired devices
119 | Set BTpairedDevices = BTAdapter.getBondedDevices();
120 |
121 | // Check for last connected device
122 | for (BluetoothDevice BTdevice : BTpairedDevices)
123 | if (IsValidAdapter(BTdevice.getName(), BTdevice.getAddress()))
124 | return ConnectDevice(BTdevice); // try to connect to the adapter
125 |
126 | return false;
127 | }
128 |
129 | private Boolean IsBlueFireDevice()
130 | {
131 | // Get all paired devices
132 | Set BTpairedDevices = BTAdapter.getBondedDevices();
133 |
134 | // Try to connect to the adapter
135 | for (BluetoothDevice BTdevice : BTpairedDevices)
136 | if (BTdevice.getName().equals(BFDeviceName))
137 | if (ConnectDevice(BTdevice)) // try to connect to the adapter and retry
138 | return true;
139 |
140 | return false;
141 | }
142 |
143 | // Connect to the Bluetooth device and Pair if needed
144 | private boolean ConnectDevice(BluetoothDevice BTdevice)
145 | {
146 | try
147 | {
148 | BTpairing = true; // ignore discovery timeout just in case pairing is needed
149 |
150 | // Get a BluetoothSocket to connect with the given BluetoothDevice
151 | try {
152 | if (Socket != null)
153 | {
154 | Socket.close();
155 | InStream = null;
156 | OutStream = null;
157 | }
158 |
159 | if (blueFire.UseInsecureConnection())
160 | Socket = BTdevice.createInsecureRfcommSocketToServiceRecord(BFCommBT2.BT_UUID);
161 | else
162 | Socket = BTdevice.createRfcommSocketToServiceRecord(BFCommBT2.BT_UUID);
163 | }
164 | catch (Exception e)
165 | {
166 | BTpairing = false;
167 | return false;
168 | }
169 | // Cancel discovery because it will slow down the connection
170 | if (BTAdapter.isDiscovering())
171 | BTAdapter.cancelDiscovery();
172 |
173 | // Connect the device through the socket. This will block until it succeeds or throws an exception.
174 | // Note, This will initiate pairing if needed.
175 | while (!Socket.isConnected())
176 | {
177 | Helper.Sleep(100);
178 | try
179 | {
180 | // Note, Socket.Connect can take from 1 to 3 seconds.
181 | // Have witnessed retries of more than 20.
182 | if (Socket != null)
183 | Socket.connect();
184 | }
185 | catch (Exception ex2)
186 | {
187 | BTpairing = false;
188 | return false;
189 | }
190 | if (Socket == null) // disconnected
191 | {
192 | BTpairing = false;
193 | return false;
194 | }
195 | }
196 | InStream = Socket.getInputStream();
197 | OutStream = Socket.getOutputStream();
198 |
199 | DeviceName = BTdevice.getName();
200 | DeviceAddress = BTdevice.getAddress();
201 |
202 | BTpairing = false;
203 |
204 | AdapterConnected();
205 |
206 | return true; // connected
207 | }
208 | catch (Exception ex)
209 | {
210 | RaiseSystemError ("CommBT2.ConnectDevice", ex);
211 | BTpairingError = true;
212 | return false;
213 | }
214 | }
215 |
216 | //endregion
217 |
218 | //region Discovery
219 |
220 | private void StartDiscovery()
221 | {
222 | UpdateState(ConnectionStates.Discovering);
223 |
224 | // Only allow discovery a set amount of time to find the adapter
225 | DiscoveryTimer = new Timer();
226 | DiscoveryTimer.schedule(new DiscoveryTimedOut(), blueFire.DiscoveryTimeout(), blueFire.DiscoveryTimeout());
227 |
228 | BTpairing = false;
229 | BTreceiving = true;
230 | BTpairingError = false;
231 | BTreceiverUnregistered = false;
232 |
233 | IntentFilter ActionFoundFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
234 | ActionFoundFilter.addAction(BluetoothDevice.ACTION_NAME_CHANGED);
235 | Context.registerReceiver(DiscoveryReceiver, ActionFoundFilter);
236 |
237 | // Start discovery.
238 | // Note, discovery of the device will be handled in the Broadcast Receiver.
239 | BTAdapter.startDiscovery();
240 |
241 | // Block until discovery finishes
242 | while (ConnectionState == ConnectionStates.Discovering)
243 | Helper.Sleep(100);
244 | }
245 |
246 | private class DiscoveryTimedOut extends TimerTask
247 | {
248 | @Override
249 | public void run()
250 | {
251 | // Check for BT receiving
252 | if (BTreceiving)
253 | {
254 | BTreceiving = false;
255 | return;
256 | }
257 | // Check for BT pairing
258 | if (BTpairing)
259 | {
260 | BTpairing = false;
261 | return;
262 | }
263 |
264 | // Stop the discovery timer (but don't nuke it)
265 | if (DiscoveryTimer != null) // just to be safe ...
266 | DiscoveryTimer.cancel();
267 |
268 | // Unregister the discovery receiver
269 | CancelDiscovery();
270 |
271 | // Did not find an adapter, display a message to the user.
272 | // Note, all messages to the user must be done here in this timer thread instead of in
273 | // the receiver.
274 | if (!BTpairingError)
275 | AdapterNotConnected();
276 | }
277 | };
278 |
279 | private void StopDiscoveryTimer()
280 | {
281 | try
282 | {
283 | if (DiscoveryTimer != null)
284 | {
285 | DiscoveryTimer.cancel();
286 | DiscoveryTimer.purge();
287 | DiscoveryTimer = null;
288 | }
289 | }
290 | catch (Exception ex){}
291 | }
292 |
293 | // Return from Bluetooth discovery broadcasts
294 |
295 | private void CancelDiscovery()
296 | {
297 | BTAdapter.cancelDiscovery();
298 | Helper.Sleep(100); // give time for all receiver events to fire
299 |
300 | while (BTAdapter.isDiscovering())
301 | Helper.Sleep(100); // give time for all receiver events to fire
302 |
303 | UnregisterReceiver();
304 | }
305 |
306 | //endregion
307 |
308 | //region Broadcast Receiver
309 |
310 | protected final BroadcastReceiver DiscoveryReceiver = new BroadcastReceiver() {
311 |
312 | public void onReceive(Context context, Intent intent) {
313 |
314 | try
315 | {
316 | if (BTreceiverUnregistered)
317 | return;
318 |
319 | String action = intent.getAction();
320 |
321 | // Check for discovery finding a device.
322 | // Note, if there are multiple devices, discovery will find the one that is connected.
323 | if ((action.equals(BluetoothDevice.ACTION_FOUND) || action.equals(BluetoothDevice.ACTION_NAME_CHANGED)) && !BTfoundDevice)
324 | {
325 | BTreceiving = true; // ignore discovery timeout
326 |
327 | // Get the Bluetooth device
328 | BluetoothDevice BTdevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
329 |
330 | if (BTdevice == null)
331 | return;
332 |
333 | String BTName = BTdevice.getName();
334 | if (BTName == null)
335 | return;
336 |
337 | // Check for a BlueFire adapter
338 | if (BTName.equals(BFDeviceName))
339 | {
340 | // Yes is is, stop the receiver and try to connect to it
341 | BTfoundDevice = true;
342 |
343 | CancelDiscovery();
344 |
345 | ConnectDevice(BTdevice);
346 |
347 | if (!IsConnected) // needed for bug when reconnecting with no pairing
348 | ConnectDevice(BTdevice);
349 |
350 | BTfoundDevice = false;
351 | }
352 | }
353 | }
354 | catch (Exception ex)
355 | {
356 | CancelDiscovery();
357 | RaiseSystemError ("CommBT2.BroadcastReceiver", ex);
358 | BTpairingError = true;
359 | }
360 | }
361 | };
362 |
363 | private void UnregisterReceiver()
364 | {
365 | // This is the only way to handle receiver already unregistered
366 | try
367 | {
368 | BTreceiverUnregistered = true;
369 | Context.unregisterReceiver(DiscoveryReceiver);
370 | }
371 | catch(Exception e) {}
372 | }
373 |
374 | //endregion
375 |
376 | //region Adapter Connected
377 |
378 | @Override
379 | protected void AdapterConnected()
380 | {
381 | StopDiscoveryTimer();
382 |
383 | super.AdapterConnected();
384 | }
385 |
386 | //endregion
387 |
388 | //region Is Data Available
389 |
390 | @Override
391 | public boolean IsDataAvailable()
392 | {
393 | try
394 | {
395 | // Check for any queued packets
396 | if (super.IsDataAvailable())
397 | return true;
398 |
399 | // Check for disconnection
400 | if (InStream == null)
401 | return false;
402 |
403 | // Check for any input packets
404 | if (InStream.available() == 0)
405 | return false;
406 |
407 | byte[] DataBuffer = GetPacketData();
408 | if (DataBuffer.length == 0)
409 | return false;
410 |
411 | // Add input packet to the queue
412 | ReceiveAdapterData(DataBuffer);
413 |
414 | return true;
415 | }
416 | catch (Exception ex)
417 | {
418 | RaiseSystemError ("CommBT2.IsDataAvailable", ex);
419 | return false;
420 | }
421 | }
422 |
423 | //endregion
424 |
425 | //region Get Packet Data
426 |
427 | // Get message data from the adapter
428 | // The data stream looks like:
429 | // Length (2) - Length of Requested Data, not Checksum
430 | // Length Check (1)
431 | // Message Data (n)
432 | // Data Checksum (1)
433 |
434 | private byte[] GetPacketData()
435 | {
436 | DataLength = 0;
437 | BufferIndex = 0;
438 | MessageLength = -1;
439 | byte[] MessageData;
440 |
441 | try
442 | {
443 | // Wait until an entire message is received from the adapter
444 | while (true)
445 | {
446 | if (InStream == null) // disconnected
447 | return new byte[0];
448 |
449 | if (InStream.available() > 0)
450 | DataByte = InStream.read();
451 | else
452 | DataByte = -1;
453 |
454 | if (DataByte < 0)
455 | if (CheckDataTimeOut())
456 | {
457 | RaiseDataTimeout();
458 | return new byte[0];
459 | }
460 | else
461 | continue;
462 |
463 | // Get the data byte
464 | StreamBuffer[BufferIndex] = (byte)DataByte;
465 |
466 | // Check for receiving the length bytes
467 | if (BufferIndex == (BFCommBT2.NofLengthBytes - 1))
468 | {
469 | DataLength = GetDataLength(StreamBuffer);
470 | if (DataLength == 0)
471 | return new byte[0];
472 | MessageLength = BFCommBT2.NofLengthBytes + DataLength + 1; // length bytes + message data + checksum
473 | }
474 |
475 | // Check for receiving the entire message
476 | else if (BufferIndex == (MessageLength - 1))
477 | {
478 | MessageData = new byte[MessageLength];
479 | System.arraycopy(StreamBuffer, 0,MessageData, 0, MessageLength);
480 | return MessageData;
481 | }
482 |
483 | BufferIndex++;
484 | }
485 | }
486 | catch (Exception ex)
487 | {
488 | if (InStream == null) // disconnected
489 | return new byte[0];
490 | else
491 | {
492 | RaiseSystemError ("CommBT2.GetPacketData", ex);
493 | return new byte[0];
494 | }
495 | }
496 | }
497 |
498 | //endregion
499 |
500 | //region Send Adapter Data
501 |
502 | @Override
503 | protected boolean SendAdapterData(byte[] DataBuffer, int DataLength) throws Exception
504 | {
505 | return SendAdapterData(DataBuffer, DataLength, true);
506 | }
507 |
508 | // Send Client Data to the BlueFire
509 | private boolean SendAdapterData(byte[] DataBuffer, int DataLength, boolean AddPrefix) throws Exception
510 | {
511 | try
512 | {
513 | if (OutStream == null || DataBuffer.length == 0)
514 | return false;
515 |
516 | super.SendAdapterData(DataBuffer, DataLength);
517 |
518 | // Add message prefix and suffix
519 | if (AddPrefix)
520 | {
521 | byte[] SendBuffer = new byte[BFCommBT2.MessagePrefix.length + DataLength + BFCommBT2.MessageSuffix.length];
522 | System.arraycopy(BFCommBT2.MessagePrefix, 0, SendBuffer, 0, BFCommBT2.MessagePrefix.length);
523 | System.arraycopy(DataBuffer, 0, SendBuffer, BFCommBT2.MessagePrefix.length, DataBuffer.length);
524 | System.arraycopy(BFCommBT2.MessageSuffix, 0, SendBuffer, BFCommBT2.MessagePrefix.length + DataLength, BFCommBT2.MessageSuffix.length);
525 | // Send the data
526 | OutStream.write(SendBuffer, 0, SendBuffer.length);
527 | }
528 | else // Send the data without a prefix and suffix
529 | OutStream.write(DataBuffer, 0, DataLength);
530 |
531 | return true;
532 | }
533 | catch (IOException ex) { } // This occurs when going out of BT range
534 | catch (Exception ex)
535 | {
536 | RaiseSystemError("CommBT2.SendClientData", ex);
537 | }
538 | return false;
539 | }
540 |
541 | //region Receive Adapter Data
542 |
543 | @Override
544 | protected void ReceiveAdapterData(byte[] DataBuffer)
545 | {
546 | super.ReceiveAdapterData(DataBuffer);
547 | }
548 |
549 | //endregion
550 |
551 | //endregion
552 |
553 | //region Disconnect
554 |
555 | @Override
556 | protected boolean Disconnect()
557 | {
558 | return Disconnect(false);
559 | }
560 |
561 | @Override
562 | public boolean Disconnect(boolean WaitForDisconnect)
563 | {
564 | if (!super.Disconnect(WaitForDisconnect))
565 | return false;
566 |
567 | UpdateState(ConnectionStates.Disconnecting);
568 |
569 | if (BTAdapter == null)
570 | {
571 | AdapterNotConnected();
572 | return false;
573 | }
574 |
575 | try
576 | {
577 | Context.unregisterReceiver(DiscoveryReceiver);
578 | }
579 | catch (Exception e) {}
580 |
581 | try
582 | {
583 | if (DiscoveryTimer != null)
584 | {
585 | DiscoveryTimer.cancel();
586 | DiscoveryTimer = null;
587 | }
588 |
589 | if (InStream != null)
590 | {
591 | InStream.close();
592 | InStream = null;
593 | }
594 | if (OutStream != null)
595 | {
596 | OutStream.close();
597 | OutStream = null;
598 | }
599 | if (Socket != null)
600 | {
601 | Socket.close();
602 | Socket = null;
603 | }
604 |
605 | // Unregister the discovery receiver
606 | CancelDiscovery();
607 |
608 | CheckWaitForDisconnect(WaitForDisconnect);
609 |
610 | return true;
611 | }
612 | catch (Exception ex)
613 | {
614 | RaiseSystemError("CommBT2.Disconnect", ex);
615 | return false;
616 | }
617 | }
618 |
619 | //endregion
620 |
621 | //region Dispose
622 |
623 | @Override
624 | public void Dispose()
625 | {
626 | super.Dispose();
627 | }
628 |
629 | //endregion
630 | }
631 |
--------------------------------------------------------------------------------
/APIDemo/src/main/java/com/bluefire/apidemo/Service.java:
--------------------------------------------------------------------------------
1 | package com.bluefire.apidemo;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.os.Handler;
6 | import android.os.Message;
7 | import android.os.Process;
8 | import android.util.Log;
9 |
10 | import com.bluefire.api.BlueFire;
11 | import com.bluefire.api.CANBusSpeeds;
12 | import com.bluefire.api.ConnectionStates;
13 | import com.bluefire.api.Const;
14 | import com.bluefire.api.RetrievalMethods;
15 | import com.bluefire.api.Vehicle;
16 |
17 | import java.util.LinkedList;
18 | import java.util.Queue;
19 |
20 | public class Service
21 | {
22 | private BlueFire blueFire;
23 |
24 | private ServiceThread serviceThread;
25 |
26 | private boolean serviceIsRunning;
27 |
28 | // Android process pid for the activity or service that instantiates the API.
29 | private int servicePid;
30 | private boolean killService= false;
31 |
32 | private ConnectionStates connectionState = ConnectionStates.NotConnected;
33 | private String connectionMessage = "";
34 |
35 | private Queue EventsQueue = new LinkedList();
36 | private ReceiveEventsThreading ReceiveEventsThread;
37 |
38 | private boolean isKeyOn;
39 |
40 | private boolean isConnecting;
41 | private boolean isConnected;
42 |
43 | private boolean IsRetrievingEngineVIN;
44 |
45 | private RetrievalMethods retrievalMethod;
46 | private int retrievalInterval;
47 |
48 | // Application settings
49 | private boolean appUseBLE;
50 | private boolean appUseBT21;
51 |
52 | private boolean appIgnoreJ1939;
53 | private boolean appIgnoreJ1708;
54 |
55 | private int appLedBrightness;
56 |
57 | private int appDiscoveryTimeOut;
58 | private int appMaxConnectAttempts;
59 | private int appMaxReconnectAttempts;
60 | private int appBluetoothRecycleAttempt;
61 | private int appBleDisconnectWaitTime;
62 |
63 | private String appDeviceId = "";
64 | private String appAdapterId = "";
65 | private boolean appConnectToLastAdapter;
66 |
67 | private String appUserName = "";
68 | private String appPassword = "";
69 | private boolean appSecureDevice = false;
70 | private boolean appSecureAdapter = false;
71 |
72 | private boolean appOptimizeDataRetrieval = false;
73 |
74 | private Context serviceContext;
75 |
76 | public Service(Context context)
77 | {
78 | serviceContext = context; // the API requires a context
79 |
80 | // Set to kill the service when the user exits.
81 | // Note, this is recommended as it will ensure that all API resources such as
82 | // Bluetooth (BLE GATT) are released.
83 | //killService = true;
84 | killService = false; // for testing
85 | servicePid = Process.myPid();
86 |
87 | // Set app variables
88 | appUseBLE = true;
89 | appUseBT21 = false;
90 |
91 | appIgnoreJ1939 = false;
92 | appIgnoreJ1708 = true;
93 |
94 | appLedBrightness = 100;
95 |
96 | appConnectToLastAdapter = false;
97 |
98 | appOptimizeDataRetrieval = true;
99 |
100 | // Setup to receive API events
101 | ReceiveEventsThread = new ReceiveEventsThreading();
102 | ReceiveEventsThread.start();
103 | }
104 |
105 | public void startService()
106 | {
107 | // Initiate the API
108 | blueFire = new BlueFire(serviceContext, eventHandler);
109 |
110 | appDiscoveryTimeOut = blueFire.DiscoveryTimeoutDefault;
111 | appMaxConnectAttempts = blueFire.MaxConnectAttemptsDefault;
112 | appMaxReconnectAttempts = blueFire.MaxReconnectAttemptsDefault;
113 | appBluetoothRecycleAttempt = blueFire.BluetoothRecycleAttemptDefault;
114 | appBleDisconnectWaitTime = blueFire.BleDisconnectWaitTimeDefault;
115 |
116 | // Simulate a service
117 | serviceIsRunning = true;
118 |
119 | serviceThread = new ServiceThread();
120 | serviceThread.start();
121 | }
122 |
123 | public void stopService()
124 | {
125 | serviceIsRunning = false;
126 |
127 | // Clear previous data from the CAN Filter
128 | blueFire.StopDataRetrieval();
129 |
130 | disconnectAdapter();
131 |
132 | blueFire.Dispose();
133 |
134 | // Kill the service to ensure all resources (like BLE) are released.
135 | // Note, this will close the BLE GATT connection if for some reason
136 | // Android is keeping it open.
137 | // Note, the app will be killed but most likely Android will restart it
138 | // so it will show up under Settings/Apps but all the App and API resources
139 | // will be stopped and restarted.
140 | if (killService)
141 | Process.killProcess(servicePid);
142 | }
143 |
144 | private class ServiceThread extends Thread
145 | {
146 | public void run()
147 | {
148 | // Connect to the adapter
149 | connectAdapter();
150 | }
151 | }
152 |
153 | // Connect
154 | public void connectAdapter()
155 | {
156 | try
157 | {
158 | isConnecting = true;
159 | isConnected = false;
160 |
161 | connectionState = ConnectionStates.NA;
162 |
163 | logNotifications("Connecting...");
164 |
165 | // Initialize adapter properties (in case they were changed)
166 | initializeAdapter();
167 |
168 | // Note, this is a blocking call and must run in it's own thread.
169 | blueFire.Connect();
170 | }
171 | catch (Exception ex) {}
172 | }
173 |
174 | private void initializeAdapter()
175 | {
176 | // Set Bluetooth adapter type
177 | blueFire.UseBLE = appUseBLE;
178 | blueFire.UseBT21 = appUseBT21;
179 |
180 | // Set to ignore data bus settings
181 | blueFire.SetIgnoreJ1939(appIgnoreJ1939);
182 | blueFire.SetIgnoreJ1708(appIgnoreJ1708);
183 |
184 | // Set the BLE Disconnect Wait Timeout.
185 | // Note, in order for BLE to release the connection to the adapter and allow reconnects
186 | // or subsequent connects, it must be completely closed. Unfortunately Android does not
187 | // have a way to detect this other than waiting a set amount of time after disconnecting
188 | // from the adapter. This wait time can vary with the Android version and the make and
189 | // model of the mobile device. The default is 2 seconds. If your app experiences numerous
190 | // unable to connect and BlueFire LE fails to show up under Bluetooth settings, try increasing
191 | // this value.
192 | blueFire.SetBleDisconnectWaitTime(appBleDisconnectWaitTime);
193 |
194 | // Set the Bluetooth discovery timeout.
195 | // Note, depending on the number of Bluetooth devices present on the mobile device,
196 | // discovery could take a long time.
197 | // Note, if this is set to a high value, the app needs to provide the user with the
198 | // capability of canceling the discovery.
199 | blueFire.SetDiscoveryTimeout(appDiscoveryTimeOut);
200 |
201 | // Set number of Bluetooth connection attempts.
202 | // Note, if the mobile device does not connect, try setting this to a value that
203 | // allows for a consistent connection. If you're using multiple adapters and have
204 | // connection problems, un-pair all devices before connecting.
205 | blueFire.SetMaxConnectAttempts(appMaxConnectAttempts);
206 | blueFire.SetMaxReconnectAttempts(appMaxReconnectAttempts);
207 | blueFire.SetBluetoothRecycleAttempt(appBluetoothRecycleAttempt);
208 |
209 | // Set the device and adapter ids
210 | blueFire.SetDeviceId(appDeviceId);
211 | blueFire.SetAdapterId(appAdapterId);
212 |
213 | // Set the connect to last adapter setting
214 | blueFire.SetConnectToLastAdapter(appConnectToLastAdapter);
215 |
216 | // Set the adapter security parameters
217 | blueFire.SetSecurity(appSecureDevice, appSecureAdapter, appUserName, appPassword);
218 |
219 | // Set to optimize data retrieval
220 | blueFire.SetOptimizeDataRetrieval(appOptimizeDataRetrieval);
221 | }
222 |
223 | private void disconnectAdapter()
224 | {
225 | try
226 | {
227 | // Note, with Firmware 3.11 there is no need to wait for the adapter
228 | // to disconnect.
229 | boolean WaitForDisconnect = isConnected; // just for code clarity
230 | blueFire.Disconnect(WaitForDisconnect);
231 | }
232 | catch(Exception e) {}
233 | }
234 |
235 | private void adapterDisconnected()
236 | {
237 | logNotifications("Adapter disconnected.");
238 |
239 | adapterNotConnected();
240 | }
241 |
242 | private void adapterNotConnected()
243 | {
244 | logNotifications("Adapter not connected.");
245 |
246 | isConnected = false;
247 | isConnecting = false;
248 |
249 | logStatus();
250 | }
251 |
252 | private void adapterReconnecting()
253 | {
254 | logNotifications("Adapter re-connecting.");
255 |
256 | isConnected = false;
257 | isConnecting = true;
258 | }
259 |
260 | private void adapterReconnected()
261 | {
262 | logNotifications("Adapter re-connected.");
263 |
264 | adapterConnected();
265 | }
266 |
267 | private void adapterNotReconnected()
268 | {
269 | logNotifications("Adapter not re-connected.");
270 |
271 | adapterNotConnected();
272 | }
273 |
274 | private void adapterNotAuthenticated()
275 | {
276 | logNotifications("Adapter not authenticated.");
277 |
278 | adapterNotConnected();
279 | }
280 |
281 | private void adapterConnected()
282 | {
283 | logNotifications("Adapter connected.");
284 |
285 | isConnected = true;
286 | isConnecting = false;
287 |
288 | // Get adapter data
289 | getAdapterData();
290 | }
291 |
292 | // Start retrieving data after connecting to the adapter
293 | private void getAdapterData()
294 | {
295 | // Check for an incompatible version.
296 | if (!blueFire.IsCompatible())
297 | {
298 | logNotifications("Incompatible Adapter.");
299 |
300 | disconnectAdapter();
301 | return;
302 | }
303 |
304 | // Get the adapter id
305 | appDeviceId = blueFire.DeviceId();
306 | appAdapterId = blueFire.AdapterId();
307 |
308 | // Get any adapter messages
309 | blueFire.GetMessages();
310 |
311 | // Start retrieving truck data
312 | getTruckData();
313 | }
314 |
315 | private void getTruckData()
316 | {
317 | // Clear previous data from the CAN Filter
318 | blueFire.StopDataRetrieval();
319 |
320 | if (Vehicle.EngineVIN == Const.NA)
321 | {
322 | IsRetrievingEngineVIN = true;
323 | blueFire.GetEngineVIN();
324 | }
325 |
326 | retrievalMethod = RetrievalMethods.OnChange; // do not use OnInterval with this many data requests
327 | retrievalInterval = blueFire.MinInterval(); // should be MinInterval or greater with this many requests
328 | int hoursInterval = 30 * Const.OneSecond; // hours only change every 3 minutes
329 |
330 | // Request data from the adapter.
331 | // Note, be careful not to request too much data at one time otherwise you run the risk of filling up
332 | // the CAN Filter buffer. You can experiment with combining data retrievals to determine how much you can
333 | // request before filling the CAN Filter buffer (you get an error if you do).
334 |
335 | blueFire.GetEngineData1(retrievalMethod, retrievalInterval); // RPM, Percent Torque, Driver Torque, Torque Mode
336 | blueFire.GetEngineData2(retrievalMethod, retrievalInterval); // Percent Load, Accelerator Pedal Position
337 | blueFire.GetEngineData3(retrievalMethod, retrievalInterval); // Vehicle Speed, Max Set Speed, Brake Switch, Clutch Switch, Park Brake Switch, Cruise Control Settings and Switches
338 | blueFire.GetOdometer(retrievalMethod, retrievalInterval); // Distance and Odometer
339 | blueFire.GetEngineHours(retrievalMethod, hoursInterval); // Total Engine Hours, Total Idle Hours
340 | blueFire.GetBrakeData(retrievalMethod, retrievalInterval); // Application Pressure, Primary Pressure, Secondary Pressure
341 | blueFire.GetBatteryVoltage(retrievalMethod, retrievalInterval); // Battery Voltage
342 | blueFire.GetFuelData(retrievalMethod, retrievalInterval); // Fuel Levels, Fuel Used, Idle Fuel Used, Fuel Rate, Instant Fuel Economy, Avg Fuel Economy, Throttle Position
343 | blueFire.GetTemps(retrievalMethod, retrievalInterval); // Oil Temp, Coolant Temp, Intake Manifold Temperature
344 | blueFire.GetPressures(retrievalMethod, retrievalInterval); // Oil Pressure, Coolant Pressure, Intake Manifold(Boost) Pressure
345 | blueFire.GetCoolantLevel(retrievalMethod, retrievalInterval); // Coolant Level
346 | }
347 |
348 | private int TimeToWrite = 9999;
349 |
350 | private void checkTruckData()
351 | {
352 | // Check the data you requested to see which one changed that triggered the DataAvailable
353 | // event. If you're not concerned with data throughput for processing the data, you can just
354 | // process all the data whether it changed or not.
355 |
356 | if (IsRetrievingEngineVIN && Vehicle.EngineVIN != Const.NA)
357 | {
358 | IsRetrievingEngineVIN = false;
359 | blueFire.StopRetrievingEngineVIN();
360 | logNotifications("Engine VIN=" + Vehicle.EngineVIN);
361 | }
362 |
363 | if (TimeToWrite > 50)
364 | {
365 | TimeToWrite = 0;
366 | logNotifications("RPM=" + Vehicle.RPM);
367 | }
368 | else
369 | TimeToWrite ++;
370 |
371 | // if (Vehicle.RPM > 0)
372 | // logNotifications("RPM=" + Vehicle.RPM);
373 | // logNotifications("PctLoad=" + Vehicle.PctLoad);
374 | // logNotifications("Speed=" + Vehicle.Speed);
375 | }
376 |
377 | private void checkKeyState()
378 | {
379 | boolean keyIsOn = blueFire.IsKeyOn();
380 |
381 | if (isKeyOn != keyIsOn)
382 | {
383 | if (keyIsOn)
384 | logNotifications("Key is On");
385 | else
386 | logNotifications("Key is Off");
387 |
388 | // Double check key change by retrieving IsCANAvailable and IsJ1708Available.
389 | // Note, only do this on change of state, not constantly.
390 | blueFire.GetKeyState();
391 |
392 | isKeyOn = keyIsOn;
393 | }
394 | }
395 |
396 | private void CANStarting()
397 | {
398 | // Get the CAN bus speed
399 | CANBusSpeeds CANBusSpeed = blueFire.CANBusSpeed();
400 |
401 | String Message;
402 | if (blueFire.IsOBD2())
403 | Message = "OBD2";
404 | else
405 | Message = "J1939";
406 | Message += " is starting, CAN bus speed is ";
407 |
408 | switch (CANBusSpeed)
409 | {
410 | case K250:
411 | Message += "250K.";
412 | break;
413 | case K500:
414 | Message += "500K.";
415 | break;
416 | default:
417 | Message += "unknown.";
418 | break;
419 | }
420 | logNotifications(Message);
421 |
422 | // Key is on so double check the key state
423 | checkKeyState();
424 |
425 | // Re-retrieve truck data
426 | getTruckData();
427 | }
428 |
429 | private void j1708Restarting()
430 | {
431 | // Re-retrieve truck data
432 | getTruckData();
433 | }
434 |
435 | private void processEvent(Message msg)
436 | {
437 | try
438 | {
439 | connectionState = ConnectionStates.values()[msg.arg1];
440 | connectionMessage = (String)msg.obj;
441 |
442 | logStatus();
443 |
444 | switch (connectionState)
445 | {
446 | case Connecting:
447 | case Discovering:
448 | case Disconnecting:
449 | case Connected:
450 | break;
451 |
452 | case IsReady:
453 | adapterConnected();
454 | break;
455 |
456 | case NotAuthenticated:
457 | adapterNotAuthenticated();
458 | break;
459 |
460 | case Disconnected:
461 | adapterDisconnected();
462 | break;
463 |
464 | case Reconnecting:
465 | adapterReconnecting();
466 | break;
467 |
468 | case Reconnected:
469 | adapterReconnected();
470 | break;
471 |
472 | case NotReconnected:
473 | adapterNotReconnected();
474 | break;
475 |
476 | case CANStarting:
477 | CANStarting();
478 | break;
479 |
480 | case J1708Restarting:
481 | j1708Restarting();
482 | break;
483 |
484 | case NotConnected:
485 | adapterNotConnected();
486 | break;
487 |
488 | case CANFilterFull:
489 | logNotifications("The CAN Filter is Full. Some data will not be retrieved.");
490 | break;
491 |
492 | case DataError:
493 | logNotifications("Adapter Data Error. " + connectionMessage);
494 | break;
495 |
496 | case Notification:
497 | logNotifications("API notification. " + connectionMessage);
498 | break;
499 |
500 | case AdapterMessage:
501 | logNotifications("Adapter message. " + connectionMessage);
502 | break;
503 |
504 | case AdapterReboot:
505 | logNotifications("Adapter Rebooting - " + connectionMessage);
506 | break;
507 |
508 | case DataTimeout:
509 | logNotifications("Adapter Data Timeout - Lost connection with the Adapter");
510 | break;
511 |
512 | case BluetoothTimeout:
513 | adapterNotConnected();
514 | logNotifications("Adapter Bluetooth Timeout - Unable to connect to Bluetooth.");
515 | break;
516 |
517 | case AdapterTimeout:
518 | adapterNotConnected();
519 | logNotifications("Adapter Connection Timeout - Bluetooth unable to connect to the Adapter.");
520 | break;
521 |
522 | case SystemError:
523 | adapterNotConnected();
524 | logNotifications("API System error. " + connectionMessage);
525 | break;
526 |
527 | case DataChanged:
528 | checkTruckData();
529 | break;
530 | }
531 |
532 | }
533 | catch (Exception e) {}
534 | }
535 |
536 | // BlueFire Event Handler Thread
537 | private class ReceiveEventsThreading extends Thread
538 | {
539 | public void run()
540 | {
541 | while (true)
542 | {
543 | if (!EventsQueue.isEmpty())
544 | {
545 | Message handleMessage = EventsQueue.poll();
546 | if (handleMessage != null)
547 | processEvent(handleMessage);
548 | }
549 | threadSleep(1); // allow other threads to execute
550 | }
551 | }
552 | }
553 |
554 | // BlueFire Event Handler
555 | private Handler eventHandler = new Handler()
556 | {
557 | @Override
558 | @SuppressLint("HandlerLeak")
559 | public void handleMessage(Message msg)
560 | {
561 | Message handleMessage = new Message();
562 | handleMessage.what = msg.what;
563 | handleMessage.obj = msg.obj;
564 |
565 | EventsQueue.add(handleMessage);
566 | }
567 | };
568 |
569 | private void logStatus()
570 | {
571 | logNotifications(connectionState.toString());
572 | }
573 |
574 | private void logNotifications(String message)
575 | {
576 | if (!message.equals(""))
577 | Log.d("BlueFire", message);
578 | }
579 |
580 | private void threadSleep(int Interval)
581 | {
582 | try
583 | {
584 | Thread.sleep(Interval);
585 | }
586 | catch(Exception ex) {}
587 | }
588 |
589 | }
590 |
--------------------------------------------------------------------------------
/APIDemo/src/main/res/drawable/bluefire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueFire-LLC/BlueFire-API-for-Android-Studio/62d5696102f6bcefa3ec0cd9b0b1f965f81ab739/APIDemo/src/main/res/drawable/bluefire.png
--------------------------------------------------------------------------------
/APIDemo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | BlueFire-API-for-Android-Studio
3 |
4 |
--------------------------------------------------------------------------------
/APIDemo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
13 |
14 |
15 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/BlueFire API Issue Report.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueFire-LLC/BlueFire-API-for-Android-Studio/62d5696102f6bcefa3ec0cd9b0b1f965f81ab739/BlueFire API Issue Report.docx
--------------------------------------------------------------------------------
/BlueFire API Issue Report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueFire-LLC/BlueFire-API-for-Android-Studio/62d5696102f6bcefa3ec0cd9b0b1f965f81ab739/BlueFire API Issue Report.pdf
--------------------------------------------------------------------------------
/BlueFire-API-for-Android-Studio.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/BueFire Android API v26.0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueFire-LLC/BlueFire-API-for-Android-Studio/62d5696102f6bcefa3ec0cd9b0b1f965f81ab739/BueFire Android API v26.0.pdf
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BlueFire-API-for-Android
2 | Android API for direct connection to the BlueFire J1939/J1708 Bluetooth Data Adapters.
3 |
4 | Version 1:
5 |
Initial version.
6 |
7 |
8 | Version 2:
9 |
Code updates.
10 |
11 |
12 | Version 3:
13 |
Handles Adapter looping errors.
14 |
15 |
16 | Version 4:
17 |
Added Adapter Name and Password retrieval and update.
18 |
Connects to any adapter that starts with the Adapter Name.
19 |
Reboots the adapter on receiving adapter errors (firmware version 2.12).
20 |
Supports Adapter Firmware 2.13.
21 |
22 |
23 | Version 5:
24 |
Added Adapter Name update to Main page.
25 |
Added Truck Make, Model, Serial No, and Unit No to Next Pages.
26 |
Added App Settings class for BlueFire settings.
27 |
Added rebooting the adapter when disconnecting.
28 |
Added LastConnectedId and ConnectToLastAdapter Bluetooth settings.
29 |
Added Incompatible version check.
30 |
31 |
Adapter Firmware 2.7 and less
32 |
Adapter Firmware 3.0 and greater
33 |
34 |
35 |
36 | Version 6:
37 |
Created an API document. Contact BlueFire Support for a copy.
38 |
Removed exposure to the Comm, J1939, and J1587 classes, and, moved all properties and methods to the Adapter class.
39 |
Added option to set the Interval on retrieving truck data (default is on change of data). This is useful when the data is coming in too fast (ie. RPM) and you want to slow it down.
40 |
Added SendPGN method and PGNData property for sending non-API defined PGNs.
41 |
Added sample code for SendPGN and MonitorPGN.
42 |
Added commons-codec-1.10.jar to the project libs folder. This is only required for the API Demo App.
43 |
Added a projects docs folder that contains the commons javadoc files. You must set the Javadoc Location project property to point to this folder.
44 |
45 |
46 | Version 7:
47 |
GetVehicleData is now threaded for performance.
48 |
Compatible with Adapter Firmware 3.x.
49 |
50 |
51 | Version 8:
52 |
Fixed retrieving J1939 Component Id (Make, Model, Serial No, Unit No).
53 |
Added retrieving J1708 VIN, Component Id and Faults.
54 |
Added additional exception handling.
55 |
56 |
57 | Version 9:
58 |
Added additional exception handling.
59 |
Added additional debug logging to the Demo App (Main).
60 |
61 |
62 | Version 10:
63 |
Added J1708 filtering.
64 |
Truck numerical data is initialized to -1.
65 |
Demo App (Main) shows NA if truck data is negative (no data).
66 |
67 |
68 | Version 11:
69 |
Renamed FWVersion property to FirmwareVersion.
70 |
Renamed HWVersion property to HardwareVersion.
71 |
J1587 filtering caters for a 0 value where appropriate.
72 |
73 |
74 | Version 12:
75 |
Supports Adapter Firmwares 3.4+.
76 |
Added User Name and Password authentication.
77 |
Added updating adapter data (led brightness) while offline to the Demo App (Main).
78 |
79 |
80 | Version 13:
81 |
Added Key State to API Demo (Key On/Off).
82 |
Renamed source folder and apk from "bluefire.apidemo" to "com.bluefire.apidemo".
83 |
84 |
85 | Version 14:
86 |
Minor improvements to the Bluetooth Discovery process.
87 |
Changed SetMaxConnectRetrys default to 10 retries.
88 |
Changed SetDiscoveryTimeOut default to 30 seconds.
89 |
90 |
91 | Version 15:
92 |
Supports Adapter Firmware 3.7.
93 |
GetVehicleData, GetFuelData, and GetEngineHours retrieves data more accurately (firmware 3.6 and lower work, but better performance with firmware 3.7).
94 |
95 |
96 | Version 16:
97 |
When J1939 and J1708 data are retrieved, J1939 data will take precedence over J1708 data.
98 |
99 |
100 | Version 17:
101 |
Supports Adapter Firmware 3.8+.
102 |
Added Get/Set PerformanceMode that will improve the retrieval of PGNs that have an interval of one second.
103 |
Minor improvement to the retrieval of vehicle data (vin, make, model, serial no).
104 |
105 |
106 | Version 18:
107 |
App heartbeat will be sent to the adapter every second.
108 |
109 |
110 | Version 19:
111 |
Supports the BLE (Bluetooth Low Energy) adapters (see limitations below).
112 |
The API will automatically find and select the correct adapter (BLE or BT21 (Bluetooth Classic)).
113 |
Added properties UseBLE, UseBT21 that will improve connection speed if set.
114 |
Added properties IsUsingBLE, IsUsingBT21 that will be set according to the type of Bluetooth connected to.
115 |
Added property MinInterval that defaults to 500 ms for BLE adapters.
116 |
Supports the new 500K CAN adapter (green Deutsch connector).
117 |
Removed the Settings class from the Demo App.
118 |
No longer compatible with Adapter firmware 2.x.
119 |
Requires Android 4+ for Bluetooth Classic adapter and 5+ for BLE adapter.
120 |
Supports the Android Studio IDE.
121 |
122 |
123 | Version 19.1:
124 |
Patch for discovering an adapter using Bluetooth Classic and Android 6.0+.
125 |
126 |
127 | Version 20.0:
128 |
Renamed the Adapter class to the BlueFire class to avoid confusion with the Android Adapter widget.
129 |
Added an Adapter BT2.1 and a BLE checkbox that will select the appropriate Adapter type. Leaving both unchecked will cause the API to auto select the Adapter type.
130 |
Added GetTransmissionGears method that will retrieve the current and selected gears from the transmission ECM if the data is available.
131 |
132 |
133 | Version 20.1:
134 |
Removed IsUsingBT21 and IsUsingBLE properties in lieu of using properties UseBT21 and UseBLE which if not set will be set automatically by the API.
135 |
The Demo App's Disconnect button will be shown immediately after connecting to allow for disconnecting while the API is attempting to discover an Adapter.
136 |
137 |
138 | Version 20.2:
139 |
The API will only raise Connection State 'Reconnected' when the Adapter is reconnected. Connection State 'AdapterConnected' will only be raised upon initial connection.
140 |
The Demo App has been modified to reflect the above 'Reconnected' Connection State.
141 |
Added API method ResetAdapter which will reset the Adapter to factory settings.
142 |
The Demo App will edit for invalid hex characters in Send PGN Data.
143 |
Fixed API fatal exception in SendPGN when sending data.
144 |
145 |
146 | Version 21.0:
147 |
Added optional Source and MID parameters to the GetVehicleInfo method.
148 |
Added optional Source and MID parameters to the GetFaults method.
149 |
Removed property IsFaultDataChanged.
150 |
Added Truck property IsJ1587Fault.
151 |
All methods take Source, PGN, and MID as integers.
152 |
Demo App shows Fault source.
153 |
154 |
155 | Version 22.0:
156 |
Added support for Adapter Firmware 3.10 and ELD Recording (see API 22.0 documentation).
157 |
Changed and renamed many properties and methods. Refer to the API documentation for all the changes.
158 |
Backward compatible with Adapter Firmware 3.7 to 3.9 (no ELD Recording).
159 |
No additional functionality except for features in Firmware 3.10 and ELD Recording.
160 |
Added Adapter Id security.
161 |
Fixed BLE issues however using the BLE Adapter requires Android 6+.
162 |
New Demo App that supports ELD Recording.
163 |
Demo App request location permissions if connecting to a BLE adapter.
164 |
API and Demo App are compiled with minimum Android version of 23.
165 |
Demo App no longer references commons-codec-1.10.
166 |
167 |
168 | Version 22.1:
169 |
Changed ConnectionStates, SleepModes, and ELD.RecordIds to be exposed outside of the BlueFire class.
170 |
Internal changes.
171 |
172 |
173 | Version 22.2:
174 |
Requires Adapter Firmware Beta 3.10.3 for ELD functionality.
175 |
Removed duplicate ELD records.
176 |
Better re-connection while ELD recording.
177 |
178 |
179 | Version 22.3:
180 |
Compatible with Adapter Firmware Beta 3.10.5 for ELD functionality.
181 |
Better time sync with the Adapter.
182 |
183 |
184 | Version 22.4:
185 |
Requires Adapter Firmware Beta 3.10.5 for ELD functionality.
186 |
Added getEngineVIN method.
187 |
Added synchronization to Truck Data methods.
188 |
Added retrievalMethod parameter to Truck Data methods.
189 |
Demo App only retrieves truck data when navigating to the specific data page.
190 |
API documentation has been updated to reflect the above changes.
191 |
192 |
193 | Version 22.5:
194 |
Requires Adapter Firmware Beta 3.10.6 for ELD functionality.
195 |
Fixed J1708 data retrieval.
196 |
Added property AndroidVersion.
197 |
Added property SyncTimeout.
198 |
Added ConnectionState CANFilterFull.
199 |
Renamed property DiscoveryTimeOut to DiscoveryTimeout.
200 |
Renamed property MaxConnectRetrys to MaxConnectAttempts.
201 |
Added method ELD.SetStreaming.
202 |
Added property ELD.LocalRecordNo.
203 |
Added ELD Enum RecordingModes.
204 |
Added property ELD.RecordingMode and method SetRecordingMode.
205 |
Added property ELD.IsRecordingLocally.
206 |
Added property ELD.IsRecordingConnected.
207 |
Added property ELD.IsRecordingDisconnected.
208 |
Included the API documentation in the GitHub repository.
209 |
Added to the API documentation Appendix instructions for manually resetting the Adapter.
210 |
211 |
212 | Version 22.6:
213 |
Requires Adapter Firmware Beta 3.10.8 for ELD functionality.
214 |
Removed VIN from GetVehicleData method.
215 |
Added Boolean return value to Truck Data methods for synchronized calls.
216 |
Added synchronized VIN retrieval to Demo App.
217 |
ELD rules are sent to the Adapter from the API.
218 |
The Adapter will reboot after ELD StopEngine if the API is not connected.
219 |
220 |
221 | Version 22.7:
222 |
Requires Adapter Firmware 3.10 for ELD functionality.
223 |
Fixed issue with retrieving VIN and Vehicle Data in the Demo App.
224 |
225 |
226 | Version 22.8:
227 |
Fixed compatability with Firmware 3.9 and below.
228 |
API will generate and update the Adapter Serial Number if it is missing. This can occur if the adapter firmware is flashed over the top of an older incompatible firmware.
229 |
230 |
231 | Version 22.9:
232 |
Requires Adapter Firmware 3.11. Note, Firmware 3.10 is broken and should be updated to 3.11.
233 |
Compatable with Firmware 3.9 and below.
234 |
API method GetEngineVIN automatically sets the sync timeout if RetrievalMethod Synchronized is specified. The default sync timeout is 2 seconds.
235 |
The call to VIN retrieval SetSyncTimeout in the Demo App has been commented out to allow the API method to set the default.
236 |
Faults have been moved to their own page in the Demo App in order to allow faults to be retrieved by themselves (recommended).
237 |
VIN and Truck data (Component Id) retrieval have been improved. It is recommended to retrieve VIN and Truck data before retrieving any other data.
238 |
239 |
240 | Version 22.10:
241 |
The API now disconnects properly from the Adapter while ELD is recording.
242 |
The Demo App disconnectAdapter method WaitForDisconnect parameter is set to false for Adapter Firmware 3.11.
243 |
244 |
245 | Version 22.11:
246 |
The SetDiscoveryTimeOut method is renamed to SetDiscoveryTimeout (TimeOut to Timeout).
247 |
Added SetAdvertisementTimeout method for use in very crowded BLE areas (like trade shows).
248 |
For BLE adapters, if the ConnectToLastAdapter and SetSecurity(SecureAdapter) are not set, the API will connect to the adapter with the strongest signal.
249 |
250 |
251 | Version 22.12:
252 |
Added method GetDistance which is the same as GetOdometer (GetOdometer actually calls GetDistance).
253 |
Added properties Truck.HiResDistance, LoResDistance, HiResOdometer, and LoResOdometer.
254 |
Truck.Odometer now returns the OEM distance (previously it returned Engine distance).
255 |
Truck.Odometer will return -1 if the OEM distance is not available (e.g. Volvo trucks).
256 |
Truck.Distance and Truck.Odometer returns the hi-resolution value unless it is not available in which case it returns the lo-resolution value.
257 |
Note that hi-resolution distance is at a 1 second ECM refresh rate while lo-resolution is at a 100 ms ECM refresh rate.
258 |
Modified the Demo App to reflect the above changes.
259 |
260 |
261 | Version 22.13:
262 |
Added a Service class that emulates using the API with an Android service.
263 |
Added a Start and Stop Service buttons to the Demo App.
264 |
265 |
266 | Version 23.0:
267 |
GetVehicleData is renamed to GetEngineId.
268 |
Added methods GetVIN and GetComponentId for retrieving non-engine ECM data.
269 |
Added synchronized calling to GetEngineVIN, GetVIN, GetEngineId, and GetComponentId.
270 |
The SetSyncTimeout method is replaced with the SyncTimeout passed as the Interval parameter along with the Synchronized Retrieval Method parameter.
271 |
Fixed the OnChange Retrieval Method that caused issues with the Adapter.
272 |
Added a Notification ConnectionState that will return any API notifications.
273 |
Added SetHeartbeatOn method that will turn the Adapter heartbeat on/off. Use with caution.
274 |
Added SetNotificationsOn method that will turn Adapter notifications on/off.
275 |
Change the Engine VIN/Id page in the Demo App to show using synchronous retrieval.
276 |
Added a VIN/ComponentId page to the Demo App that shows using asynchronous retrieval.
277 |
Added a Test All button to the Demo App that retrieves all the data at once to test loading the connection.
278 |
Improved connection reliability with beta Firmware 3.12.x.
279 |
280 |
281 | Version 23.1:
282 |
Added property OptimizeDataRetrieval that optimizes retrieval of data when the same data is available from both J1939 and J1708 ECMs. Recommended.
283 |
Added a J1708Restarting ConnectionState that will be raised if J1708 data retrieval is restarting (see Demo App).
284 |
Not selecting a connection type (BLE or BT21) will auto connect properly.
285 |
The Demo App re-retrieves data when the ConnectionState J1708Restarting is raised.
286 |
The Demo App shows Key On/Off properly for J1708 vehicles.
287 |
Better J1708 data retrieval with Firmware 3.12.
288 |
No longer supports Android 4+ and Android 5+.
289 |
Compatible with Android 7.1 devices that use Android 6 BLE firmware.
290 |
291 |
292 | Version 23.2:
293 |
Added retrieval of transmission temperature (Truck.TransTemp) to method GetTemps.
294 |
Added retrieval of primary and secondary fuel gauge levels (Truck.PrimaryFuelLevel and SecondaryFuelLevel to GetFuelData.
295 |
Changed property OptimizeDataRetrieval to OptimizeDataRetrieval() and SetOptimizeDataRetrieval(boolean value).
296 |
Improved OptimizeDataRetrieval. Note, this update is required if using OptimizeDataRetrieval.
297 |
The Demo App shows Key Off when disconnected (see checkKeyState and showConnectButton).
298 |
Critical patch for retrieving Adapter settings (sleep mode, led brightness, ignore databuses, j1708 availability).
299 |
300 |
301 | Version 23.3:
302 |
Fixed bug in 23.2 that caused GetEngineVIN and GetEngineId to error.
303 |
Added methods GetTruckVIN and GetTruckId for retrieving the OEM VIN and Component Id (Make/Model/SerialNo).
304 |
Added methods StopRetrievingEngineVIN and StopRetrievingEngineId. Call these after Truck.EngineVIN and/or Truck.EngineMake have been retrieved.
305 |
Added methods StopRetrievingTruckVIN and StopRetrievingTruckId. Call these after Truck.VIN and/or Truck.Make have been retrieved.
306 |
Removed methods GetVIN and GetComponentId.
307 |
Specifying OnChange Retrieval Method now works. The previous release changed it internally to OnInterval.
308 |
Added AdapterMessage ConnectionState that will be raised when there is a message from the Adapter.
309 |
Further improvements to J1708 data retrieval and connection stability.
310 |
Improved API and Adapter error reporting.
311 |
Updated the Demo App and Service to demonstrate the above changes.
312 |
313 |
314 | Version 23.4:
315 |
Critical patch to fix BLE connection issues.
316 |
Fixed J1939 ELD VIN characters being truncated from a 17 character VIN.
317 |
Better re-connection when the adapter reboots.
318 |
Added property HardwareType with values HardwareTypes.HW_1_1 (old adapter), HW_6_Pin, and HW_9_Pin.
319 |
Renamed PerformanceMode to IsPerformanceModeOn.
320 |
Renamed SetPerformanceMode to SetPerformanceModeOn.
321 |
Added PerformanceInterval and SetPerformanceInterval.
322 |
Removed the ELD Waiting RecordId as it is no longer sent by the adapter.
323 |
Added getTruckInfoThread to Demo App.
324 |
Disconnecting the adapter in the Demo App no longer stops ELD recording.
325 |
326 |
327 | Version 23.5:
328 |
The default interval for GetEngineVIN and GetTruckVIN is changed from 2 seconds to 3 seconds.
329 |
The default interval for GetEngineId and GetTruckId is changed from 2 seconds to 5 seconds.
330 |
ELD.Date returns the correct UTC date.
331 |
Renamed method ELD.Time to ELD.Date.
332 |
Added ELD.LocalDate that returns the local date of the device the API is running on.
333 |
Added ELD local date to the Demo App.
334 |
335 |
336 | Version 23.6:
337 |
Added ELD.StartUpload and ELD.StopUpload methods that must be called prior to and after uploading ELD records.
338 |
Slightly faster connection if using SetConnectToLastAdapter especially in crowded Bluetooth areas.
339 |
Added ConnectionState 'Heartbeat' that will be raised when a heartbeat is received from the adapter.
340 |
ConnectionState 'DataChanged' is no longer raised when a heartbeat is received from the adapter. It is now only raised when actual data is received from the adapter.
341 |
The Demo App sets WaitForDisconnect prior to disconnecting. This is highly recommended if re-connection is possible immediately after disconnecting.
342 |
ConnectionState 'Connected' has been removed from the Demo App. This was confusing as it only appled to the Bluetooth connection and not the adapter connection.
343 |
The Demo App shows the heartbeat count when the ConnectionState 'Heartbeat' is raised.
344 |
In the Demo App, showStatus{} is moved from the beginning to the end of the event handler.
345 |
Added ConnectionState 'Heartbeat' to the Demo App's event handler.
346 |
Enabled 'LED Brightness' and 'Connect to Last Adapter' in the Demo App so that it can be changed prior to connecting to the adapter.
347 |
The ELD Upload and Delete buttons are enabled in the Demo App anytime there are ELD records no matter if ELD recording is occurring or not.
348 |
349 |
350 | Version 23.7:
351 |
Added Security setting Secure Device which secures the device (phone, tablet, etc) to an adapter. One device can be secured to many adapters (one to many relationship).
352 |
Security setting Secure Adapter remains unchanged and secures the device to a single adapter and secures the adapter to the one device (one to one relationship).)
353 |
Security setting UserName and Password secures the device to an adapter. A device can be secured to many adapters and many adapters can be secured to a device (many to many relationship).
354 |
Security (UserName, Password, Adapter Id, Device Id) are all encrypted with AES encryption.
355 |
Requires Adapter Firmware 3.14 for all security updates.
356 |
Fixed Bluetooth Classic (BT21) reconnection issues. Please see the documentation for important information about Bluetooth Classic reconnection.
357 |
Fixed Bluetooth Classic 'Connect to Last Adapter' not working.
358 |
The API will automatically reconnect when the IgnoreJ1939 or Ignore1708 are changed.
359 |
With Firmware 3.14, ELD uploading with only 'Record while Disconnected' set will not perform any connected recording while uploading.
360 |
Compatible with Adapter Firmware 3.13 and below. For Firmware 3.11 - 3.13 only Secure Adapter is available. For Firmware 3.9 and below, only UserName and Password security is available.
361 |
Updated the Demo App to reflect the above changes.
362 |
363 |
364 | Version 23.8:
365 |
Critical patch for retrieving data after a reconnection.
366 |
MaxConnectAttempts now works for BLE adapters.
367 |
The default MaxConnectAttempts is changed from 10 to 5;
368 |
Added SetBluetoothRecycleAttempt method that will recycle (turn off/on) Bluetooth at the specified connection and reconnection attempt. The default is 2 (second attempt).
369 |
Updated the Demo App to reflect the above changes.
370 |
Updated the documentation to reflect the above changes.
371 |
372 |
373 | Version 23.9:
374 |
Added method SetIgnoreDatabuses that will update the IgnoreJ1939 and IgnoreJ1708 settings and send them to the adapter.
375 |
Added ConnectionState ELDConnected that will be raised after the API receives ELD startup data from the adapter.
376 |
The ConnectionState Authenticated will now be raised after the API receives startup data from the adapter. This data includes PerformanceMode, SleepMode, LEDBrightness, IgnoreJ1939, IgnoreJ1708, HardwareType and any messages.
377 |
The UseBLE, UseBT21, IgnoreJ1939, and IgnoreJ1708 settings will be set appropriately if the HardwareType is HW_6_Pin.
378 |
Added CheckKeyState to showHeartbeat in the Demo app to ensure that the key state is checked if the ECMs are powered down.
379 |
Updated the Demo App to reflect the above changes.
380 |
Updated the documentation to reflect the above changes.
381 |
382 |
383 | Version 23.10:
384 |
Improved adapter connection and reconnection. The last, secured, or previous adapter id will be used to attempt a direct connection to the adapter prior to scanning for an adapter.
385 |
The SetNotificationsOn method will start/stop API notifications along with Adapter notifications.
388 |
The Demo app saves settings when they are changed.
389 |
390 |
391 | Version 23.11:
392 |
Added BleDisconnectWaitTime property and SetBleDisconnectWaitTime method that will wait for BLE to close the GATT connection. The default is 2000 (2 seconds).
393 |
Bluetooth is no longer turned off when the the API disconnects from the adapter if Bluetooth was turned on to connect the first time.
394 |
Updated the Demo App to reflect the above changes.
396 |
397 |
398 | Version 23.12:
399 |
Added method GetELDData that will only retrieve RPM, Speed, Distance/Odometer, and Total Hours with optimum settings. See the Demo app getTruckData, group 6.
400 |
Added method GetKeyState that will double check if the ECM is powered up and sending data. See the Demo app function checkKeyState for how to use it properly.
401 |
Added ConnectionState J1939Started that will be raised when the API is connected and the J1939 CAN bus is available (key is turned on). See the Demo app function setJ1939Starting.
402 |
Added property CANBusSpeed that will be returned when the ConnectionState J1939Started is raised.
403 |
Updated the Demo App to reflect the above changes.
404 |
405 |
406 | Version 23.13:
407 |
More reliable event handling.
408 |
Faster BLE re-connection and elimination of the BluetoothGattCallback.onConnectionStateChange exception.
409 |
The UseBLE, UseBT21 will not be changed if the HardwareType is HW_6_Pin. This is to allow for BT21 and BLE 6-pin adapters. The IgnoreJ1939, and IgnoreJ1708 settings will still be set appropriately.
410 |
ConnectionState J1939Starting will be raised only after connecting to the adapter, either when the key is turned on or immediately after authentication if the key is already on.
411 |
Added option for the Demo App to kill itself on exiting (see onBackPressed).
412 |
413 |
414 | Version 23.14:
415 |
GetELDData settings are changed to RPM and Speed - OnInterval, one second; Distance/Odometer - OnChange, 5 seconds; Total Hours - OnChange, 10 seconds.
416 |
Added property IsOBD2 which will be set when CAN is starting (CANStarting, see below).
424 |
Added property IgnoreOBD2 which when set to false (connecting to OBD2) will set IgnoreJ1939 and IgnoreJ1708 true.
425 |
Property IgnoreOBD2 accepts the OBD2.CANSettings parameter. Warning! Changing this from the default may cause ECM faults.
426 |
Renamed ConnectionState J1939Starting to CANStarting to reflect CAN Starting for either J1939 or OBD2.
427 |
Removed property SetIgnoreDataBuses because the properties IgnoreJ1939/J1708/OBD2 are required for the Adapter to connect to the correct ECUs.
428 |
Removed method UpdateSecurity because security parameters must be set prior to connecting to the Adapter.
429 |
Added property SetDisconnectedReboot that will instruct the Adapter to reboot at a set interval when not connected to the App (Firmware 3.12+). Note with Firmware 3.12+ the interval is fixed at one hour. With Firmware 3.15+ the interval is set with the property.
430 |
Added properties IsKeyOn and IsKeyOff that will check for key on/off and if off will set RPM, Speed, PctLoad, PctTorque, DrvPctTorque to 0.
431 |
Added property SendAllPackets that will instruct the Adapter to send all J1939 VIN, Make, Model, etc data packets at one time instead of in a conversational manner. This also applies to the ELD VIN.
432 |
The Adapter will wait to initiate a CAN connection until all Adapter data has been retrieved by the API. The previous API version initiated the CAN connection when the Adapter is authenticated.
433 |
The ConnectionState AdapterMessage will always return a complete message.
434 |
Compatible with Firmware 3.7.
435 |
The Demo App will show the API Beta version.
436 |
Updated the Demo App to reflect the above changes.
437 |
438 |
439 | Version 24.1:
440 |
Added Property Force500kBus that will instruct the Adapter to connect only to a 500K CAN bus.
441 |
Fixed SleepMode not being initialized by the App or Service.
442 |
Internal fixes to potential issues.
443 |
Fixed Starting Service in the Demo App.
444 |
445 |
446 | Version 24.2:
447 |
Properties IgnoreJ1708 and IgnoreOBD2 default to true (ignore both J1708 and OBD2) and IgnoreJ1939 defaults to false (retrieve J1939 data); If you want to retrieve J1708 or OBD2 data you must explicitly set them to false.
448 |
The API will not allow retrieving J1939/J1708 data along with OBD2 data (see below).
449 |
Setting IgnoreJ1939 or IgnoreOBD2 to false (retrieve J1939/J1708 data) will set IgnoreOBD2 true (ignore OBD2).
450 |
Setting IgnoreOBD2 to false (retrieve OBD2 data) will set IgnoreJ1939 and IgnoreJ1708 true (ignore them both).
451 |
Setting both UseBLE and UseBT21 on will cause the API to auto discover the Adapter (same as if they are both set off).
452 |
If UseBLE/UseBT21 are changed, or both set, or both not set, the API will reset the Previous Adapter Id, Discovery Timeout, and Advertisement Timeout.
453 |
Updated the Demo App to reflect the above changes.
454 |
455 |
456 | Version 24.3:
457 |
Renamed the MonitorPGN method to StartMonitoringPGN.
458 |
Added multi-packet (BAM/RTS) PGN retrieval to the StartMonitoringPGN, StopMonitoringPGN, and RequestPGN methods.
459 |
SendPGN method parameters have changed to (Source, PGN, Priority, PGNData).
460 |
Updated the Demo App to reflect the above changes.
461 |
Updated the Demo App to show how to monitor multiple PGNs.
462 |
463 |
464 | Version 24.4:
465 |
Fixed retrieving data from a 6-pin adapter.
466 |
467 |
468 | Version 24.5:
469 |
Fixed backward compatibility with 3.7 Firmware on a 2.1 (Bluetooth Classic) adapter.
470 |
471 |
472 | Version 25.0:
473 |
Changed event handling to be faster, more accurate and more reliable.
474 |
475 |
Uses queues to ensure messages are received.
476 |
Events are received as soon as they are raised by the API.
477 |
Connection State and any Messages (if appropriate) are returned with the event.
478 |
Duplicate events no longer occur.
479 |
Imperative that events are allowed to be handled without interruption.
480 |
API will attempt to deliver an event for 2 seconds before ignoring it.
481 |
See the Demo App for correct implementation.
482 |
483 |
Added ConnectionState AdapterReboot.
484 |
Removed ConnectionState AdapterConnected.
485 |
Renamed ConnectionState Authenticated to Connected.
486 |
Renamed ConnectionState CommTimeout to DataTimeout.
487 |
Renamed ConnectionState ConnectTimeout to BluetoothTimeout.
488 |
Added property ConnectAttempt.
489 |
Added property ReconnectAttempt.
490 |
Renamed property Message to ConnectionMessage.
491 |
Removed property ReconnectReason.
492 |
Removed property NotificationMessage.
493 |
Removed property NotificationLocation.
494 |
Removed method ClearMessages.
495 |
Removed method ClearNotificationMessage.
496 |
Fixed setting Notifications On/Off.
497 |
Fixed setting UserName without a Password.
498 |
Fixed updating security to the Adapter.
499 |
Fixed AdapterTimeout when connecting to a factory reset Adapter.
500 |
Added ignoring the Retarder and Exhaust ECMs due to failing to adhere to the J1939 standard and causing undue network traffic.
501 |
Updated the Demo App to reflect the above changes.
502 |
503 |
504 | Version 25.1:
505 |
Added method SetKeepJ1708PortOpen that will cause the Adapter to keep the J1708 Com port open. This can be used for trucks that do not adhere to the J1708 spec and raise a fault when the Adapter is connected.
506 |
507 |
508 | Version 25.2:
509 |
Added Interval to Send/Monitoring.
510 |
Added Send button to Send/Monitoring. Note, sending PGN data will continue based on the interval until either stopped, navigated to Truck/ELD data, or disconnected.
511 |
512 |
513 | Version 25.3:
514 |
Fixed retrieving J1708 (6-pin) Distance and Odometer when they are different. Note, this can occur when the engine or cab/body/instrument ECMs are changed and the distance values are not synced between the two.
515 |
516 |
517 | Version 25.4:
518 |
API is compiled with Target SDK 26 and Min SDK 22. Previous version was Target SDK 25 and Min SDK 23.
519 |
The Demo App checks for Min SDK 23 and Location Permission granted by the user.
520 |
521 |
522 | Version 25.5:
523 |
API is compiled with Target SDK 28 and Min SDK 22.
524 |
525 |
526 | Version 26.0:
527 |
Removed Eclipse support.
528 |
Renamed "Truck" to "Vehicle".
529 |
The ResetAdapter method now resets the adapter correctly. See the documentation for the changes.
530 |
Open sourced Bluetooth communication code Comm, CommBLE, CommBT2. Open source Comm modules use Pascal notation.
531 |
Added regions to Main, Comm, CommBLE, and CommBT2.
532 |
Updated documentation to v26.0 (pdf).
533 |
API is compiled with Target SDK 29 and Min SDK 23 (Android 5-10).
534 |
535 |
536 | Version 27.0:
537 |
Android version 6 is not longer suppported.
538 |
API is compiled with Min SDK 24 and Target SDK 31 (Android 7-12).
539 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.1.2'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | google()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## For more details on how to configure your build environment visit
2 | # http://www.gradle.org/docs/current/userguide/build_environment.html
3 | #
4 | # Specifies the JVM arguments used for the daemon process.
5 | # The setting is particularly useful for tweaking memory settings.
6 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
7 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
8 | #
9 | # When configured, Gradle will run in incubating parallel mode.
10 | # This option should only be used with decoupled projects. More details, visit
11 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
12 | # org.gradle.parallel=true
13 | #Sat Feb 26 15:34:17 PST 2022
14 | org.gradle.jvmargs=-Xmx1536m
15 | android.useAndroidX=true
16 | android.enableJetifier=true
17 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueFire-LLC/BlueFire-API-for-Android-Studio/62d5696102f6bcefa3ec0cd9b0b1f965f81ab739/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Feb 26 14:56:39 PST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Wed Dec 11 14:33:54 PST 2019
8 | sdk.dir=C\:\\Program Files (x86)\\Android\\android-sdk
9 |
--------------------------------------------------------------------------------
/output.json:
--------------------------------------------------------------------------------
1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"25.5","enabled":true,"outputFile":"APIDemo-debug.apk","fullName":"debug","baseName":"debug"},"path":"APIDemo-debug.apk","properties":{}}]
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':APIDemo'
2 |
--------------------------------------------------------------------------------