7 Replies Latest reply on Nov 11, 2014 8:11 AM by Pietro Francesco Maggi

    Printing from Android to a Bluetooth Zebra printer without pairing

    Pietro Francesco Maggi

      I'm looking for a way to print from an Android device to a Zebra printer over bluetooth without previously pairing it.

       

      The printer does not have an authentication PIN so pairing seems to have issues with the Android interface: https://code.google.com/p/android/issues/detail?id=26041

       

      I've done some testing using the createInsecureRfcommSocketToServiceRecord API with mixed results. Using below code I'm able to print on the MZ320 from Android v4.1.2 devices but the same program fails on Android v4.4.3. So far I've tested:

       

      • MC40 JB v4.1.2 - Works
      • TC55 JB v4.1.2 - Works
      • TC70 KK v4.4.3 - Printer lights up blue led signaling a Bluetooth request but no printing
      • Nexus 7 (2012) KK v4.4.3 - Printer lights up blue led signaling a Bluetooth request but no printing

       

      The only difference in the logs running the app is that I get this warning on KK devices:

      11-06 12:10:05.824    2136-2178/com.pietromaggi.sample.printing W/BluetoothAdapter﹕ getBluetoothService() called with no BluetoothManagerCallback  
      11-06 12:10:05.834    2136-2178/com.pietromaggi.sample.printing D/BluetoothSocket﹕ connect(), SocketState: INIT, mPfd: {ParcelFileDescriptor: FileDescriptor[59]}  
      

      But I don't think that this is what generate the issue:

      core/java/android/bluetooth/BluetoothAdapter.java - platform/frameworks/base - Git at Google

       

      Any idea/suggestion?

       

      ~Pietro

       

      public void pairPrinter()  {  
              final UUID SerialPortServiceClass_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");  
              final BluetoothAdapter BA = BluetoothAdapter.getDefaultAdapter();  
              final String PrinterBsid = "00:22:58:0E:E7:87"; // This is My Printer Bluetooth MAC Address  
        
        
              Thread t = new Thread(new Runnable() {  
                  @Override  
                  public void run() {  
                      OutputStream sOut;  
                      BluetoothSocket socket;  
                      BA.cancelDiscovery();  
        
        
                      BluetoothDevice BD = BA.getRemoteDevice(PrinterBsid);  
                      try {  
                          socket = BD.createInsecureRfcommSocketToServiceRecord(SerialPortServiceClass_UUID);  
                      } catch (IOException e) {  
                          return;  
                      }  
        
        
                      if (!socket.isConnected()) {  
                          try {  
                              socket.connect();  
                              sOut = socket.getOutputStream();  
      //                        sOut.write(("Hello World\n").getBytes());  
                              String cpclData = "! 0 200 200 210 1\r\n"  
                                      + "TEXT 4 0 30 40 This is a CPCL test.\r\n"  
                                      + "FORM\r\n"  
                                      + "PRINT\r\n";  
                              sOut.write(cpclData.getBytes());  
                              sOut.close();  
                          } catch (IOException e) {  
                              e.printStackTrace();  
                          }  
                      }  
        
        
                      try {  
                          Thread.sleep(1000);  
                          socket.close();  
                          BA.cancelDiscovery();  
                      } catch (IOException e) {  
                          e.printStackTrace();  
                      } catch (InterruptedException e) {  
                          e.printStackTrace();  
                      }  
                  }  
              });  
        
        
              t.start();  
          }  
      
        • Re: Printing from Android to a Bluetooth Zebra printer without pairing
          Robin West

          Hi Pietro,

          You have the right idea here.  The issue is the way Android handles pairing with devices using Bluetooth standards 2.0 and below.  The only way to send info to these devices is to enter a pin on the device, or not pair at all and open a straight insecure socket to it.

          Your code looks fine, but apparently KK made a small change to the socket creation method. Try this for lines 15-20 of your sample:

           

          BluetoothDevice BD = BA.getRemoteDevice(PrinterBsid);
          try {
              socket = BD.createRfcommSocketToServiceRecord();
          } catch (Exception e) {Log.e("","Error creating socket");}
          
          try {
              socket.connect();
              Log.e("","Connected");
          } catch (IOException e) {
              Log.e("",e.getMessage());
              try {
                    Log.e("","trying fallback...");
                    socket =(BluetoothSocket) BD.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(BD,1);
              }
              catch (Exceptio e2) {
                    Log.e("",e2.getMessage());
              }
          }
          

          You might still get the error, but you can ignore it and create the socket now.

           

          Hope this works for you.

            • Re: Re: Printing from Android to a Bluetooth Zebra printer without pairing
              Pietro Francesco Maggi

              Hi Robin,

              thanks for the help.

              The problem is that using your solution I get a request for a PIN code. And that is something that I'd like to avoid :-)

               

              I think that the problem is that, with the changes in Android v4.4 I cannot start to write immediately on the Bluetooth Socket after having opened it. Putting my thread to sleep for 1s after opening the socket seems to work.

              Now, I need to find a better (more reliable) way to wait for the socket to be usable.

              Below code works on a TC70 with Android v4.4.3:

               

                  public void pairPrinter()  {
                      final UUID SerialPortServiceClass_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
                      final BluetoothAdapter BA = BluetoothAdapter.getDefaultAdapter();
                      final String PrinterBsid = "00:22:58:0E:E7:87";
              
              
                      Thread t = new Thread(new Runnable() {
                          @Override
                          public void run() {
                              OutputStream sOut;
                              BluetoothSocket socket;
                              BA.cancelDiscovery();
              
              
                              BluetoothDevice BD = BA.getRemoteDevice(PrinterBsid);
                              try {
                                  socket = BD.createInsecureRfcommSocketToServiceRecord(SerialPortServiceClass_UUID);
              
              
                                  if (!socket.isConnected()) {
                                      socket.connect();
                                      Thread.sleep(1000); // <-- WAIT FOR SOCKET
                                  }
                                  sOut = socket.getOutputStream();
                                  String cpclData = "! 0 200 200 210 1\r\n"
                                          + "TEXT 4 0 30 40 This is a CPCL test.\r\n"
                                          + "FORM\r\n"
                                          + "PRINT\r\n";
                                  sOut.write(cpclData.getBytes());
                                  sOut.close();
              
                                  socket.close();
                                  BA.cancelDiscovery();
              
              
                              } catch (IOException e) {
                                  Log.e("","IOException");
                                  e.printStackTrace();
                                  return;
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }
                          }
                      });
              
                      t.start();
                  }
              

               

              ~Pietro

              1 of 1 people found this helpful
                • Re: Re: Printing from Android to a Bluetooth Zebra printer without pairing
                  Pietro Francesco Maggi

                  Just a note to explain that, while BluetoothSocket.connect was blocking on Android v4.1.2, this is no more the case for Android v4.4.3.


                  This is why it's possible with Android v4.1 to start using the socket as soon as it is open.

                   

                  ~Pietro

                    • Re: Re: Re: Printing from Android to a Bluetooth Zebra printer without pairing
                      Robin West

                      Just so I know how to answer, I want to clarify.  Ignore pairing from the Android settings and just use the app.  Does the Java code you have in your post make the app ask for a pin?  It shouldn't, but I want to make sure. 

                      If this is the case, will it work for you?

                       

                      For your timing issue, I know it's kind of kludgy, but have you tried:

                       

                      if (!socket.isConnected()) {  
                          socket.connect();  
                          int i = 3000;
                          while ( ( !socket.isConnected() ) || ( i > 0 ) )
                                i--;
                      
                      }
                      


                      It can take up to 3 seconds to establish a Bluetooth connection sometimes.  Not often, but just to be safe.


                      - Robin

                        • Re: Re: Re: Re: Printing from Android to a Bluetooth Zebra printer without pairing
                          Pietro Francesco Maggi

                          Hi Robin,

                          the code I posted result in the printer printing without any pairing and without the need of an authentication PIN.

                           

                          Regarding the timing issue, your code, or something more battery friendly like the one below does not works as it seems that isConnected returns true even if in reality is not...

                           

                           

                                              if (!socket.isConnected()) {
                                                  socket.connect();
                                              }
                          
                          
                                              int limit = 1000; //
                                              while ((limit>0) && (!socket.isConnected())) {
                                                  Thread.sleep(1);
                                                  limit--;
                                              }
                                              Log.d(TAG_BLUETOOTH, "limit is <" + limit + ">");
                                              if (0 == limit) {
                                                  Log.e("","Slow socket!");
                                                  throw new IOException("SlowSocket");
                                              }
                          

                           

                          In this case you always get limit is <1000>.

                          Debugging the code is of no help as you introduce more than enough delay if you insert a breakpoint after the socket.connect() call.

                           

                          I'm looking for a way to register a callback without much luck at this moment.

                           

                          ~Pietro