Reputation: 38
I am experiencing an issue where the onServiceConnected
callback is not invoked in my client code, despite the service's onCreate
and onBind
methods being called successfully and return a binder. The service is started, onBind return true, but onServiceConnected
is not called. This issue occurs when attempting to bind to a custom service from a client within a different module.
I've written this PrinterManagerClient, everything works fine except the "onServiceConnected" that don't work.
internal class PrinterManagerClient(private val context: Context): AutoCloseable {
private val timeout = 30L
private var service: IPrinterManager? = null
private var isBound = false
private val serviceBoundLatch = CountDownLatch(1)
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
logger.i("PrinterManagerService Connected")
[email protected] = IPrinterManager.Stub.asInterface(service)
isBound = true
serviceBoundLatch.countDown()
}
override fun onServiceDisconnected(className: ComponentName) {
logger.i("PrinterManagerService Disconnected")
[email protected] = null
isBound = false
}
}
init {
logger.i("Binding service")
Intent().apply {
component = ComponentName(
"com.ingenico.ingp.printer.service",
"com.ingenico.ingp.printer.service.PrinterManagerService"
)
val resolveInfo = context.packageManager.resolveService(this, PackageManager.MATCH_DEFAULT_ONLY)
if (resolveInfo == null) {
logger.e("PrinterManagerService not found! Is it installed?")
} else {
logger.i("PrinterManagerService found.")
val isServiceBound = context.bindService(this, connection, Context.BIND_AUTO_CREATE)
if (!isServiceBound) {
logger.e("Service binding failed")
}
}
}
}
private fun ensureServiceBound(): Boolean {
return isBound || awaitServiceBound()
}
private fun awaitServiceBound(): Boolean {
return try {
serviceBoundLatch.await(timeout, TimeUnit.SECONDS)
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
false
}
}
private fun <T> executeServiceOperation(operation: () -> T): T {
if (!ensureServiceBound()) {
//throw IllegalStateException("Service not bound and timed out") // Disabled for testing purposes
}
return operation()
}
fun getPrinter(printerName: String): IPrinter? = executeServiceOperation {
service!!.getPrinter(printerName)
}
fun getRegisteredPrinters(): List<ParcelablePrinterInstanceInfo> = executeServiceOperation {
service!!.getRegisteredPrinters()
}
fun getSupportedPrinters(): List<ParcelablePrinterDriverInfo> = executeServiceOperation {
service!!.getSupportedPrinters()
}
fun getDefaultPrinterName(): String = executeServiceOperation {
service!!.defaultPrinterName
}
fun setDefaultPrinter(
printerName: String
): Boolean = executeServiceOperation {
service!!.setDefaultPrinter(printerName)
}
override fun close() {
if (isBound) {
context.unbindService(connection)
isBound = false
}
}
}
And here is the service:
class PrinterManagerService : Service() {
private lateinit var manager: AndroidPrinterManager
private val binder = object : IPrinterManager.Stub() {
override fun getPrinter(printerName: String): IPrinter? {
return manager.getPrinter(printerName)?.toAidl()
}
override fun getDefaultPrinterName(): String =
manager.defaultPrinter
override fun getRegisteredPrinters(): MutableList<ParcelablePrinterInstanceInfo> {
return manager.registeredPrinters.map { it.toAidl() }.toMutableList()
}
override fun setDefaultPrinter(printerName: String): Boolean {
return try {
manager.defaultPrinter = printerName
true
} catch (e: IllegalArgumentException) {
false
}
}
override fun getSupportedPrinters(): MutableList<ParcelablePrinterDriverInfo> {
return manager.supportedPrinters.map { it.toAidl() }.toMutableList()
}
}
override fun onBind(intent: Intent): IBinder {
logger.i("onBind")
return binder
}
override fun onCreate() {
logger.i("onCreate")
super.onCreate()
instance = this
serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
manager = AndroidPrinterManager(this)
}
override fun onDestroy() {
logger.i("onDestroy")
super.onDestroy()
manager.close()
serviceScope.cancel() // Cancel all coroutines
}
}
When using context.bindService
, the service's onCreate
and onBind
execute properly, and a binder is returned, yet the onServiceConnected
callback in my client isn't triggered. I've already made the suggested manifest modifications from similar Stack Overflow discussions, confirming the service setup is correct. The main issue lies in the non-execution of the callback.
Returning a simple Binder() doesn't work. I'm using the applicationContext here.
Upvotes: 0
Views: 69