Merge "Fix OOM of metro clock" into udc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d756cad817
@@ -26,6 +26,7 @@ import android.util.TypedValue
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.OnAttachStateChangeListener
|
import android.view.View.OnAttachStateChangeListener
|
||||||
import android.view.ViewTreeObserver
|
import android.view.ViewTreeObserver
|
||||||
|
import android.view.ViewTreeObserver.OnGlobalLayoutListener
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
@@ -88,6 +89,15 @@ constructor(
|
|||||||
) {
|
) {
|
||||||
var clock: ClockController? = null
|
var clock: ClockController? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
|
smallClockOnAttachStateChangeListener?.let {
|
||||||
|
field?.smallClock?.view?.removeOnAttachStateChangeListener(it)
|
||||||
|
smallClockFrame?.viewTreeObserver
|
||||||
|
?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
|
||||||
|
}
|
||||||
|
largeClockOnAttachStateChangeListener?.let {
|
||||||
|
field?.largeClock?.view?.removeOnAttachStateChangeListener(it)
|
||||||
|
}
|
||||||
|
|
||||||
field = value
|
field = value
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
smallLogBuffer?.log(TAG, DEBUG, {}, { "New Clock" })
|
smallLogBuffer?.log(TAG, DEBUG, {}, { "New Clock" })
|
||||||
@@ -130,44 +140,62 @@ constructor(
|
|||||||
}
|
}
|
||||||
value.events.onWeatherDataChanged(it)
|
value.events.onWeatherDataChanged(it)
|
||||||
}
|
}
|
||||||
value.smallClock.view.addOnAttachStateChangeListener(
|
|
||||||
|
smallClockOnAttachStateChangeListener =
|
||||||
object : OnAttachStateChangeListener {
|
object : OnAttachStateChangeListener {
|
||||||
var pastVisibility: Int? = null
|
var pastVisibility: Int? = null
|
||||||
override fun onViewAttachedToWindow(view: View?) {
|
override fun onViewAttachedToWindow(view: View?) {
|
||||||
value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
|
value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
val smallClockFrame = view.parent as FrameLayout
|
smallClockFrame = view.parent as FrameLayout
|
||||||
pastVisibility = smallClockFrame.visibility
|
smallClockFrame?.let {frame ->
|
||||||
smallClockFrame.viewTreeObserver.addOnGlobalLayoutListener(
|
pastVisibility = frame.visibility
|
||||||
ViewTreeObserver.OnGlobalLayoutListener {
|
onGlobalLayoutListener = OnGlobalLayoutListener {
|
||||||
val currentVisibility = smallClockFrame.visibility
|
val currentVisibility = frame.visibility
|
||||||
if (pastVisibility != currentVisibility) {
|
if (pastVisibility != currentVisibility) {
|
||||||
pastVisibility = currentVisibility
|
pastVisibility = currentVisibility
|
||||||
// when small clock visible, recalculate bounds and sample
|
// when small clock visible,
|
||||||
if (currentVisibility == View.VISIBLE) {
|
// recalculate bounds and sample
|
||||||
smallRegionSampler?.stopRegionSampler()
|
if (currentVisibility == View.VISIBLE) {
|
||||||
smallRegionSampler?.startRegionSampler()
|
smallRegionSampler?.stopRegionSampler()
|
||||||
|
smallRegionSampler?.startRegionSampler()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
frame.viewTreeObserver
|
||||||
|
.addOnGlobalLayoutListener(onGlobalLayoutListener)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewDetachedFromWindow(p0: View?) {
|
override fun onViewDetachedFromWindow(p0: View?) {
|
||||||
|
smallClockFrame?.viewTreeObserver
|
||||||
|
?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
value.largeClock.view.addOnAttachStateChangeListener(
|
value.smallClock.view
|
||||||
|
.addOnAttachStateChangeListener(smallClockOnAttachStateChangeListener)
|
||||||
|
|
||||||
|
largeClockOnAttachStateChangeListener =
|
||||||
object : OnAttachStateChangeListener {
|
object : OnAttachStateChangeListener {
|
||||||
override fun onViewAttachedToWindow(p0: View?) {
|
override fun onViewAttachedToWindow(p0: View?) {
|
||||||
value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
|
value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewDetachedFromWindow(p0: View?) {
|
override fun onViewDetachedFromWindow(p0: View?) {
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
value.largeClock.view
|
||||||
|
.addOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
var smallClockOnAttachStateChangeListener: OnAttachStateChangeListener? = null
|
||||||
|
@VisibleForTesting
|
||||||
|
var largeClockOnAttachStateChangeListener: OnAttachStateChangeListener? = null
|
||||||
|
private var smallClockFrame: FrameLayout? = null
|
||||||
|
private var onGlobalLayoutListener: OnGlobalLayoutListener? = null
|
||||||
|
|
||||||
private var isDozing = false
|
private var isDozing = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -307,7 +335,6 @@ constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
isRegistered = true
|
isRegistered = true
|
||||||
|
|
||||||
broadcastDispatcher.registerReceiver(
|
broadcastDispatcher.registerReceiver(
|
||||||
localeBroadcastReceiver,
|
localeBroadcastReceiver,
|
||||||
IntentFilter(Intent.ACTION_LOCALE_CHANGED)
|
IntentFilter(Intent.ACTION_LOCALE_CHANGED)
|
||||||
@@ -346,6 +373,12 @@ constructor(
|
|||||||
largeRegionSampler?.stopRegionSampler()
|
largeRegionSampler?.stopRegionSampler()
|
||||||
smallTimeListener?.stop()
|
smallTimeListener?.stop()
|
||||||
largeTimeListener?.stop()
|
largeTimeListener?.stop()
|
||||||
|
clock?.smallClock?.view
|
||||||
|
?.removeOnAttachStateChangeListener(smallClockOnAttachStateChangeListener)
|
||||||
|
smallClockFrame?.viewTreeObserver
|
||||||
|
?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
|
||||||
|
clock?.largeClock?.view
|
||||||
|
?.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTimeListeners() {
|
private fun updateTimeListeners() {
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ package com.android.keyguard
|
|||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.testing.AndroidTestingRunner
|
import android.testing.AndroidTestingRunner
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.view.ViewTreeObserver
|
||||||
|
import android.widget.FrameLayout
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
|
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
|
||||||
@@ -83,7 +84,13 @@ class ClockEventControllerTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var bgExecutor: Executor
|
@Mock private lateinit var bgExecutor: Executor
|
||||||
@Mock private lateinit var featureFlags: FeatureFlags
|
@Mock private lateinit var featureFlags: FeatureFlags
|
||||||
@Mock private lateinit var smallClockController: ClockFaceController
|
@Mock private lateinit var smallClockController: ClockFaceController
|
||||||
|
@Mock private lateinit var smallClockView: View
|
||||||
|
@Mock private lateinit var smallClockViewTreeObserver: ViewTreeObserver
|
||||||
|
@Mock private lateinit var smallClockFrame: FrameLayout
|
||||||
|
@Mock private lateinit var smallClockFrameViewTreeObserver: ViewTreeObserver
|
||||||
@Mock private lateinit var largeClockController: ClockFaceController
|
@Mock private lateinit var largeClockController: ClockFaceController
|
||||||
|
@Mock private lateinit var largeClockView: View
|
||||||
|
@Mock private lateinit var largeClockViewTreeObserver: ViewTreeObserver
|
||||||
@Mock private lateinit var smallClockEvents: ClockFaceEvents
|
@Mock private lateinit var smallClockEvents: ClockFaceEvents
|
||||||
@Mock private lateinit var largeClockEvents: ClockFaceEvents
|
@Mock private lateinit var largeClockEvents: ClockFaceEvents
|
||||||
@Mock private lateinit var parentView: View
|
@Mock private lateinit var parentView: View
|
||||||
@@ -99,8 +106,12 @@ class ClockEventControllerTest : SysuiTestCase() {
|
|||||||
fun setUp() {
|
fun setUp() {
|
||||||
whenever(clock.smallClock).thenReturn(smallClockController)
|
whenever(clock.smallClock).thenReturn(smallClockController)
|
||||||
whenever(clock.largeClock).thenReturn(largeClockController)
|
whenever(clock.largeClock).thenReturn(largeClockController)
|
||||||
whenever(smallClockController.view).thenReturn(TextView(context))
|
whenever(smallClockController.view).thenReturn(smallClockView)
|
||||||
whenever(largeClockController.view).thenReturn(TextView(context))
|
whenever(smallClockView.parent).thenReturn(smallClockFrame)
|
||||||
|
whenever(smallClockView.viewTreeObserver).thenReturn(smallClockViewTreeObserver)
|
||||||
|
whenever(smallClockFrame.viewTreeObserver).thenReturn(smallClockFrameViewTreeObserver)
|
||||||
|
whenever(largeClockController.view).thenReturn(largeClockView)
|
||||||
|
whenever(largeClockView.viewTreeObserver).thenReturn(largeClockViewTreeObserver)
|
||||||
whenever(smallClockController.events).thenReturn(smallClockEvents)
|
whenever(smallClockController.events).thenReturn(smallClockEvents)
|
||||||
whenever(largeClockController.events).thenReturn(largeClockEvents)
|
whenever(largeClockController.events).thenReturn(largeClockEvents)
|
||||||
whenever(clock.events).thenReturn(events)
|
whenever(clock.events).thenReturn(events)
|
||||||
@@ -302,8 +313,38 @@ class ClockEventControllerTest : SysuiTestCase() {
|
|||||||
verify(configurationController).removeCallback(any())
|
verify(configurationController).removeCallback(any())
|
||||||
verify(batteryController).removeCallback(any())
|
verify(batteryController).removeCallback(any())
|
||||||
verify(keyguardUpdateMonitor).removeCallback(any())
|
verify(keyguardUpdateMonitor).removeCallback(any())
|
||||||
|
verify(smallClockController.view)
|
||||||
|
.removeOnAttachStateChangeListener(underTest.smallClockOnAttachStateChangeListener)
|
||||||
|
verify(largeClockController.view)
|
||||||
|
.removeOnAttachStateChangeListener(underTest.largeClockOnAttachStateChangeListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun registerOnAttachStateChangeListener_validate() = runBlocking(IMMEDIATE) {
|
||||||
|
verify(smallClockController.view)
|
||||||
|
.addOnAttachStateChangeListener(underTest.smallClockOnAttachStateChangeListener)
|
||||||
|
verify(largeClockController.view)
|
||||||
|
.addOnAttachStateChangeListener(underTest.largeClockOnAttachStateChangeListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun registerAndRemoveOnGlobalLayoutListener_correctly() = runBlocking(IMMEDIATE) {
|
||||||
|
underTest.smallClockOnAttachStateChangeListener!!.onViewAttachedToWindow(smallClockView)
|
||||||
|
verify(smallClockFrame.viewTreeObserver).addOnGlobalLayoutListener(any())
|
||||||
|
underTest.smallClockOnAttachStateChangeListener!!.onViewDetachedFromWindow(smallClockView)
|
||||||
|
verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun registerOnGlobalLayoutListener_RemoveOnAttachStateChangeListener_correctly() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
underTest.smallClockOnAttachStateChangeListener!!
|
||||||
|
.onViewAttachedToWindow(smallClockView)
|
||||||
|
verify(smallClockFrame.viewTreeObserver).addOnGlobalLayoutListener(any())
|
||||||
|
underTest.unregisterListeners()
|
||||||
|
verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any())
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user