Loading packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +51 −18 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.util.TypedValue import android.view.View import android.view.View.OnAttachStateChangeListener import android.view.ViewTreeObserver import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.widget.FrameLayout import androidx.annotation.VisibleForTesting import androidx.lifecycle.Lifecycle Loading Loading @@ -88,6 +89,15 @@ constructor( ) { var clock: ClockController? = null set(value) { smallClockOnAttachStateChangeListener?.let { field?.smallClock?.view?.removeOnAttachStateChangeListener(it) smallClockFrame?.viewTreeObserver ?.removeOnGlobalLayoutListener(onGlobalLayoutListener) } largeClockOnAttachStateChangeListener?.let { field?.largeClock?.view?.removeOnAttachStateChangeListener(it) } field = value if (value != null) { smallLogBuffer?.log(TAG, DEBUG, {}, { "New Clock" }) Loading Loading @@ -130,44 +140,62 @@ constructor( } value.events.onWeatherDataChanged(it) } value.smallClock.view.addOnAttachStateChangeListener( smallClockOnAttachStateChangeListener = object : OnAttachStateChangeListener { var pastVisibility: Int? = null override fun onViewAttachedToWindow(view: View?) { value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context)) if (view != null) { val smallClockFrame = view.parent as FrameLayout pastVisibility = smallClockFrame.visibility smallClockFrame.viewTreeObserver.addOnGlobalLayoutListener( ViewTreeObserver.OnGlobalLayoutListener { val currentVisibility = smallClockFrame.visibility smallClockFrame = view.parent as FrameLayout smallClockFrame?.let {frame -> pastVisibility = frame.visibility onGlobalLayoutListener = OnGlobalLayoutListener { val currentVisibility = frame.visibility if (pastVisibility != currentVisibility) { pastVisibility = currentVisibility // when small clock visible, recalculate bounds and sample // when small clock visible, // recalculate bounds and sample if (currentVisibility == View.VISIBLE) { smallRegionSampler?.stopRegionSampler() smallRegionSampler?.startRegionSampler() } } }) } frame.viewTreeObserver .addOnGlobalLayoutListener(onGlobalLayoutListener) } } } override fun onViewDetachedFromWindow(p0: View?) { smallClockFrame?.viewTreeObserver ?.removeOnGlobalLayoutListener(onGlobalLayoutListener) } } }) value.largeClock.view.addOnAttachStateChangeListener( value.smallClock.view .addOnAttachStateChangeListener(smallClockOnAttachStateChangeListener) largeClockOnAttachStateChangeListener = object : OnAttachStateChangeListener { override fun onViewAttachedToWindow(p0: View?) { value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context)) } 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 set Loading Loading @@ -307,7 +335,6 @@ constructor( return } isRegistered = true broadcastDispatcher.registerReceiver( localeBroadcastReceiver, IntentFilter(Intent.ACTION_LOCALE_CHANGED) Loading Loading @@ -346,6 +373,12 @@ constructor( largeRegionSampler?.stopRegionSampler() smallTimeListener?.stop() largeTimeListener?.stop() clock?.smallClock?.view ?.removeOnAttachStateChangeListener(smallClockOnAttachStateChangeListener) smallClockFrame?.viewTreeObserver ?.removeOnGlobalLayoutListener(onGlobalLayoutListener) clock?.largeClock?.view ?.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener) } private fun updateTimeListeners() { Loading packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +44 −3 Original line number Diff line number Diff line Loading @@ -18,7 +18,8 @@ package com.android.keyguard import android.content.BroadcastReceiver import android.testing.AndroidTestingRunner import android.view.View import android.widget.TextView import android.view.ViewTreeObserver import android.widget.FrameLayout import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository Loading Loading @@ -83,7 +84,13 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var bgExecutor: Executor @Mock private lateinit var featureFlags: FeatureFlags @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 largeClockView: View @Mock private lateinit var largeClockViewTreeObserver: ViewTreeObserver @Mock private lateinit var smallClockEvents: ClockFaceEvents @Mock private lateinit var largeClockEvents: ClockFaceEvents @Mock private lateinit var parentView: View Loading @@ -99,8 +106,12 @@ class ClockEventControllerTest : SysuiTestCase() { fun setUp() { whenever(clock.smallClock).thenReturn(smallClockController) whenever(clock.largeClock).thenReturn(largeClockController) whenever(smallClockController.view).thenReturn(TextView(context)) whenever(largeClockController.view).thenReturn(TextView(context)) whenever(smallClockController.view).thenReturn(smallClockView) 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(largeClockController.events).thenReturn(largeClockEvents) whenever(clock.events).thenReturn(events) Loading Loading @@ -302,6 +313,36 @@ class ClockEventControllerTest : SysuiTestCase() { verify(configurationController).removeCallback(any()) verify(batteryController).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 { Loading Loading
packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +51 −18 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.util.TypedValue import android.view.View import android.view.View.OnAttachStateChangeListener import android.view.ViewTreeObserver import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.widget.FrameLayout import androidx.annotation.VisibleForTesting import androidx.lifecycle.Lifecycle Loading Loading @@ -88,6 +89,15 @@ constructor( ) { var clock: ClockController? = null set(value) { smallClockOnAttachStateChangeListener?.let { field?.smallClock?.view?.removeOnAttachStateChangeListener(it) smallClockFrame?.viewTreeObserver ?.removeOnGlobalLayoutListener(onGlobalLayoutListener) } largeClockOnAttachStateChangeListener?.let { field?.largeClock?.view?.removeOnAttachStateChangeListener(it) } field = value if (value != null) { smallLogBuffer?.log(TAG, DEBUG, {}, { "New Clock" }) Loading Loading @@ -130,44 +140,62 @@ constructor( } value.events.onWeatherDataChanged(it) } value.smallClock.view.addOnAttachStateChangeListener( smallClockOnAttachStateChangeListener = object : OnAttachStateChangeListener { var pastVisibility: Int? = null override fun onViewAttachedToWindow(view: View?) { value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context)) if (view != null) { val smallClockFrame = view.parent as FrameLayout pastVisibility = smallClockFrame.visibility smallClockFrame.viewTreeObserver.addOnGlobalLayoutListener( ViewTreeObserver.OnGlobalLayoutListener { val currentVisibility = smallClockFrame.visibility smallClockFrame = view.parent as FrameLayout smallClockFrame?.let {frame -> pastVisibility = frame.visibility onGlobalLayoutListener = OnGlobalLayoutListener { val currentVisibility = frame.visibility if (pastVisibility != currentVisibility) { pastVisibility = currentVisibility // when small clock visible, recalculate bounds and sample // when small clock visible, // recalculate bounds and sample if (currentVisibility == View.VISIBLE) { smallRegionSampler?.stopRegionSampler() smallRegionSampler?.startRegionSampler() } } }) } frame.viewTreeObserver .addOnGlobalLayoutListener(onGlobalLayoutListener) } } } override fun onViewDetachedFromWindow(p0: View?) { smallClockFrame?.viewTreeObserver ?.removeOnGlobalLayoutListener(onGlobalLayoutListener) } } }) value.largeClock.view.addOnAttachStateChangeListener( value.smallClock.view .addOnAttachStateChangeListener(smallClockOnAttachStateChangeListener) largeClockOnAttachStateChangeListener = object : OnAttachStateChangeListener { override fun onViewAttachedToWindow(p0: View?) { value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context)) } 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 set Loading Loading @@ -307,7 +335,6 @@ constructor( return } isRegistered = true broadcastDispatcher.registerReceiver( localeBroadcastReceiver, IntentFilter(Intent.ACTION_LOCALE_CHANGED) Loading Loading @@ -346,6 +373,12 @@ constructor( largeRegionSampler?.stopRegionSampler() smallTimeListener?.stop() largeTimeListener?.stop() clock?.smallClock?.view ?.removeOnAttachStateChangeListener(smallClockOnAttachStateChangeListener) smallClockFrame?.viewTreeObserver ?.removeOnGlobalLayoutListener(onGlobalLayoutListener) clock?.largeClock?.view ?.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener) } private fun updateTimeListeners() { Loading
packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +44 −3 Original line number Diff line number Diff line Loading @@ -18,7 +18,8 @@ package com.android.keyguard import android.content.BroadcastReceiver import android.testing.AndroidTestingRunner import android.view.View import android.widget.TextView import android.view.ViewTreeObserver import android.widget.FrameLayout import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository Loading Loading @@ -83,7 +84,13 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var bgExecutor: Executor @Mock private lateinit var featureFlags: FeatureFlags @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 largeClockView: View @Mock private lateinit var largeClockViewTreeObserver: ViewTreeObserver @Mock private lateinit var smallClockEvents: ClockFaceEvents @Mock private lateinit var largeClockEvents: ClockFaceEvents @Mock private lateinit var parentView: View Loading @@ -99,8 +106,12 @@ class ClockEventControllerTest : SysuiTestCase() { fun setUp() { whenever(clock.smallClock).thenReturn(smallClockController) whenever(clock.largeClock).thenReturn(largeClockController) whenever(smallClockController.view).thenReturn(TextView(context)) whenever(largeClockController.view).thenReturn(TextView(context)) whenever(smallClockController.view).thenReturn(smallClockView) 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(largeClockController.events).thenReturn(largeClockEvents) whenever(clock.events).thenReturn(events) Loading Loading @@ -302,6 +313,36 @@ class ClockEventControllerTest : SysuiTestCase() { verify(configurationController).removeCallback(any()) verify(batteryController).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 { Loading