I am working on an Android app that needs to perform a clean-up task (disconnect BLE devices) when the whole application goes to background. I implemented the standard ActivityLifecycleCallbacks and do my book-keeping in the Application class. All is working good as long as I use my AppCompatActivity instances within my package.
class MainApplication : Application(), Application.ActivityLifecycleCallbacks {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(this)
}
/// Activity counter
var startedActivities = AtomicInteger(0)
private fun activityStarted() {
if (startedActivities.incrementAndGet() == 1) {
Log.d("PICKERTEST", ">>> APPLICATION STARTED")
}
}
private fun activityStopped() {
if (startedActivities.decrementAndGet() == 0) {
Log.d("PICKERTEST", ">>> APPLICATION STOPPED")
}
}
/// Activity lifecycle callbacks
override fun onActivityStarted(activity: Activity) {
activityStarted()
}
override fun onActivityStopped(activity: Activity) {
activityStopped()
}
...
MY PROBLEM: The trouble starts when I have to pick files (for example a Firmware Update) using the system activities. In this case, I don't get callbacks for the picker activity and my app believes it gets paused, as soon as the picker appears. This disconnects the BLE device and, once I get back from the file picker, I cannot upload the firmware file to the device.
The code to open the file picker is pretty standard:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
pickButton.setOnClickListener { pickFile() }
}
private fun pickFile() {
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
this.addCategory(Intent.CATEGORY_OPENABLE)
this.type = "*/*"
}
startActivityForResult(intent, 0)
}
...
This opens up a system activity with a standard OS picker. According to adb shell dumpsys activity:
ActivityRecord{e05754 u0 com.android.documentsui/.picker.PickActivity t162}]
This activity comes from the android.documentsui:
BaseActivity > https://android.googlesource.com/platform/packages/apps/DocumentsUI/+/android-cts-8.0_r16/src/com/android/documentsui/BaseActivity.java
This package is not androidx-based and uses the standard android.app.Activity. To be fair, I am not sure if that is the issue, or if lifecycle callbacks just don't get called when I run an activity from a different package.
I can of course add a custom callback to MainApplication, to notify that we are running an external Activity
class MainApplication : Application(), Application.ActivityLifecycleCallbacks {
...
/// Custom callback
fun onStartActivityForResult() {
Log.d("PICKERTEST", "onStartActivityForResult")
activityStarted()
}
fun onActivityResult() {
Log.d("PICKERTEST", "onActivityResult")
activityStopped()
}
}
and call it in my Activity
class MainActivity : AppCompatActivity() {
...
private fun pickFile() {
...
val mainApplication = applicationContext as? MainApplication
mainApplication?.onStartActivityForResult()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val mainApplication = applicationContext as? MainApplication
mainApplication?.onActivityResult()
}
}
This is however a hack and also does not cover the case in which my Application is paused while showing the file picker.
Does anyone know a solution for listening to lifecycle events of external activities?