mazenrashed / Printooth

A well documented, high-level Android interface that makes printing via bluetooth printers easier
Mozilla Public License 2.0
400 stars 113 forks source link

Failed to find Printer #61

Open stg-andrei opened 4 years ago

stg-andrei commented 4 years ago

Hello, I am trying to connect to my DPP-250 http://www.datecs.bg/en/products/61 But when I try to pair with the printer I get Scanning and it never stops + if I hit back I get an error: I tried to debug this for hours without succes sadly

E/ActivityThread: Activity com.mazenrashed.printooth.ui.ScanningActivity has leaked IntentReceiver com.mazenrashed.printooth.utilities.Bluetooth$3@8a6a644 that was originally registered here. Are you missing a call to unregisterReceiver()?
    android.app.IntentReceiverLeaked: Activity com.mazenrashed.printooth.ui.ScanningActivity has leaked IntentReceiver com.mazenrashed.printooth.utilities.Bluetooth$3@8a6a644 that was originally registered here. Are you missing a call to unregisterReceiver()?

This is my fragment:

package scs.myApp.ro.Fragments

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageButton
import android.widget.Toast
import com.mazenrashed.printooth.Printooth
import com.mazenrashed.printooth.data.printable.Printable
import com.mazenrashed.printooth.data.printable.RawPrintable
import com.mazenrashed.printooth.data.printable.TextPrintable
import com.mazenrashed.printooth.data.printer.DefaultPrinter
import com.mazenrashed.printooth.ui.ScanningActivity
import com.mazenrashed.printooth.utilities.Printing
import com.mazenrashed.printooth.utilities.PrintingCallback
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.fragment_print_invoice.*

import scs.myApp.ro.R

class PrintInvoice : Fragment(), PrintingCallback {

    companion object {
        fun newInstance(): PrintInvoice {
            return PrintInvoice()
        }
    }
    override fun connectingWithPrinter() {
        Toast.makeText(activity, "Connecting to printer", Toast.LENGTH_SHORT).show()
    }

    override fun connectionFailed(error: String) {
        Toast.makeText(activity, error, Toast.LENGTH_SHORT).show()
    }

    override fun onError(error: String) {
        Toast.makeText(activity, error, Toast.LENGTH_SHORT).show()
    }

    override fun onMessage(message: String) {
        Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
    }

    override fun printingOrderSentSuccessfully() {
        Toast.makeText(activity, "Order sent to printer", Toast.LENGTH_SHORT).show()
    }

    private var printing: Printing?=null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(scs.myApp.ro.R.layout.fragment_print_invoice, container, false)

        getActivity()?.setTitle(getString(R.string.drawer_title_task))

        if (printing != null)
            printing!!.printingCallback = this

        val btnPiarUnpair = view.findViewById(R.id.btnPiarUnpair) as Button
        val btnPrint = view.findViewById(R.id.btnPrint) as Button

        btnPiarUnpair.setOnClickListener {
            if (Printooth.hasPairedPrinter())
                Printooth.removeCurrentPrinter()
            else {
                startActivityForResult(
                    Intent(activity, ScanningActivity::class.java),
                    ScanningActivity.SCANNING_FOR_PRINTER
                )
                changePairAndUnpair()
            }
        }

        btnPrint.setOnClickListener {
            if (!Printooth.hasPairedPrinter())
                startActivityForResult(
                    Intent(activity, ScanningActivity::class.java),
                    ScanningActivity.SCANNING_FOR_PRINTER
                )
            else {
                printText()
            }
        }

        return  view
    }

    private fun changePairAndUnpair() {
        if (Printooth.hasPairedPrinter())
            btnPiarUnpair.text = "Unpair ${Printooth.getPairedPrinter()?.name}"
        else
            btnPiarUnpair.text = "Pair with Printer"
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == ScanningActivity.SCANNING_FOR_PRINTER && resultCode == Activity.RESULT_OK)
            initPrinting()
        changePairAndUnpair()
    }

    private fun initPrinting() {
        if (Printooth.hasPairedPrinter())
            printing = Printooth.printer()
        if (printing != null)
            printing!!.printingCallback = this
    }

    private fun printText() {
        val printables = ArrayList<Printable>()
        printables.add(RawPrintable.Builder(byteArrayOf(27,104,4)).build())

        printables.add(TextPrintable.Builder()
            .setText("Hello world from print!")
            .setCharacterCode(DefaultPrinter.CHARCODE_PC1252)
            .setNewLinesAfter(1)
            .build())

        printables.add(TextPrintable.Builder()
            .setText("Hello world custom!")
            .setLineSpacing(DefaultPrinter.LINE_SPACING_30)
            .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
            .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_BOLD)
            .setUnderlined(DefaultPrinter.UNDERLINED_MODE_ON)
            .setNewLinesAfter(1)
            .build())

        printing!!.print(printables)
    }
}

I call Printooth.init(this)

In my mainActivity as such:

open class MainActivity() : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener, TasksFragment.OnFragmentInteractionListener {

    lateinit var tasksFragment: TasksFragment
    lateinit var homepageFragment: HomepageFragment
    lateinit var settingsFragment: SettingsFragment
    lateinit var printInvoice: PrintInvoice

    override fun onCreate(savedInstanceState: Bundle?) {

        Printooth.init(this)
...
Gustavomgu commented 3 years ago

Hi. I am facing the same problem in my application. With older android versions works fine, but when my app is instaled in a Android 10 device the bluetooth search don't work. I tested this with the Printooth sample app and the same problem happened. Debbuging the project I noticed that the function bluetoothAdapter.startDiscovery(); is not return a True value. I debbuged the Printooth source code but I couldn't see what is causing the trobble.

Bluetooth.java: public void startScanning() { IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); context.registerReceiver(scanReceiver, filter); bluetoothAdapter.startDiscovery(); }

(P.S. If I search the devices in the smartphone bluetooth screen, then the devices appears in the app list) .

wrpura commented 3 years ago

I think there is problem with DiscoveryCallback. This is my discoveryCallback function in kotlin :

fun discoveryCallback() {
    bluetooth.setDiscoveryCallback(object : DiscoveryCallback {
        override fun onDiscoveryStarted() {
            Log.d("Bluetooth","Discovery started")

            var pairedPrinter = PairedPrinter.getPairedPrinter()
            devices.clear() // array of devices
            printers.clear() // array of printers, recycler view

            for ( (index, device) in bluetooth.pairedDevices.withIndex() ){
                var printer = Printer()
                printer.name = device.name
                printer.address = device.address
                if (pairedPrinter!= null){
                    printer.status = pairedPrinter.address == printer.address
                }
                printers.add(index, printer)
                Log.d("printer", printer.name) // log printer's name
            }
            adapter.notifyDataSetChanged()
        }

        override fun onDiscoveryFinished() {
            Log.d("Bluetooth","Discovery ended")
        }

        override fun onDeviceFound(device: BluetoothDevice) {
            Log.d("Bluetooth", "Device found" + device.address)
        }

        override fun onDevicePaired(device: BluetoothDevice) {
            Log.d("Bluetooth", "Device Paired " + device.address)
            adapter.notifyDataSetChanged()
        }

        override fun onDeviceUnpaired(device: BluetoothDevice) {
            Log.d("Bluetooth", "Device unpaired " + device.address)
            adapter.notifyDataSetChanged()
        }

        override fun onError(message: String) {
            Toast.makeText(context, "Maaf! Terjadi error.", Toast.LENGTH_SHORT)
        }

    })
}

It's working just fine and able to print paired device's names in Pie (real device, Mi 6X), but got a problem with android 10 (real device, Redmi 2 Prime, LineageOS), unable to log anything on discovery callback.

(P.S. I'm using version 1.2.2)

Gustavomgu commented 3 years ago

I actually solved my problem with android 10. For that i had to ask for permissions in run-time and ask for LOCATION_SERVICE. ` if((ContextCompat.checkSelfPermission(getApplicationContext() ,Manifest.permission.ACCESS_FINE_LOCATION)) == PackageManager.PERMISSION_GRANTED){ // Function that do some stuff } else { ActivityCompat.requestPermissions(Activity.this, new String[] {ACCESS_FINE_LOCATION,Manifest.permission.BLUETOOTH,Manifest.permission.BLUETOOTH_ADMIN,Manifest.permission.WRITE_EXTERNAL_STORAGE},1); }

                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                                LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
                                if (!lm.isLocationEnabled()) {
                                    startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                                }
                            }`

This is a snipet of what I had to do in order to the device search work properly. This was made in my app, in the function that use the printer.