I am implementing a call answer screen. In this screen, I am using both proximity sensor and power manager wake lock to create the effect of screen turning off when the phone is close to your face. I've managed to implement the feature, however it is causing memory leak. Since I detected the leak when the fragment is still simple and contains few code, I've removed several classes and functions to trace and confirm the cause of the leak. I've managed to narrow down the cause of the leak to PowerManager.WakeLock.
this is the code that I use to implement the feature in the fragment. I've tried to release the wake lock on multiple point in fragment lifecycle, however it still causes memory leak.
override val sensorManager: SensorManager
get() = requireContext().getSystemService(Context.SENSOR_SERVICE) as SensorManager
override var proximitySensor: Sensor? = null
override val powerManager: PowerManager =
requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager
override val lock: PowerManager.WakeLock = powerManager.newWakeLock(
PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
PROXIMITY_WAKE_LOG_TAG
)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
activity?.onBackPressedDispatcher?.addCallback {
activity?.finishAndRemoveTask()
}
}
override fun onResume() {
super.onResume()
proximitySensor?.let { proximity ->
sensorManager.apply {
registerListener(
this@AnswerFragment,
proximity,
SensorManager.SENSOR_DELAY_NORMAL
)
}
}
}
override fun onPause() {
super.onPause()
sensorManager.unregisterListener(this)
if (lock.isHeld) {
lock.release()
}
}
override fun onDestroyView() {
super.onDestroyView()
proximitySensor = null
if (lock.isHeld) {
lock.release()
}
_binding = null
}
override fun onDestroy() {
if (lock.isHeld) {
lock.release()
}
super.onDestroy()
}
override fun onSensorChanged(event: SensorEvent?) {
if (event?.values?.get(0) == 0.0f) {
// Object is near phone, turn off screen
lock.acquire()
} else {
// Object is not near phone, turn on screen
if (lock.isHeld) {
lock.release()
}
}
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
As a side note: I am also getting this error in my log
WakeLock finalized while still held
This is a known issue. See the LeakCanary issue and the underlying tools issue. For now, I recommend that you consider it to be a false positive, and ignore the leak.