Merge "Fix OOM of metro clock" into udc-qpr-dev am: d756cad817

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23785706

Change-Id: I51cb03c7ab493ba61c5daaffe880c9abaff7bf04
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot
2023-07-07 19:23:15 +00:00
committed by Automerger Merge Worker
2 changed files with 95 additions and 21 deletions

View File

@@ -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,
// recalculate bounds and sample
if (currentVisibility == View.VISIBLE) { if (currentVisibility == View.VISIBLE) {
smallRegionSampler?.stopRegionSampler() smallRegionSampler?.stopRegionSampler()
smallRegionSampler?.startRegionSampler() 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() {

View File

@@ -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,6 +313,36 @@ 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 {