Merge "Fix memory leak of MediaControlPanel" into udc-dev am: 2f0a41a189

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

Change-Id: I73653496e85ff59b961d8ff843475ea3df5241a3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Jernej Virag
2023-06-22 18:58:20 +00:00
committed by Automerger Merge Worker
4 changed files with 43 additions and 24 deletions

View File

@@ -21,6 +21,8 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.Configuration import android.content.res.Configuration
import android.database.ContentObserver
import android.provider.Settings
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.util.Log import android.util.Log
import android.util.MathUtils import android.util.MathUtils
@@ -64,6 +66,7 @@ import com.android.systemui.util.Utils
import com.android.systemui.util.animation.UniqueObjectHostView import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.animation.requiresRemeasuring import com.android.systemui.util.animation.requiresRemeasuring
import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.time.SystemClock import com.android.systemui.util.time.SystemClock
import com.android.systemui.util.traceSection import com.android.systemui.util.traceSection
import java.io.PrintWriter import java.io.PrintWriter
@@ -105,6 +108,7 @@ constructor(
private val mediaFlags: MediaFlags, private val mediaFlags: MediaFlags,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val globalSettings: GlobalSettings,
) : Dumpable { ) : Dumpable {
/** The current width of the carousel */ /** The current width of the carousel */
var currentCarouselWidth: Int = 0 var currentCarouselWidth: Int = 0
@@ -169,6 +173,13 @@ constructor(
private var carouselLocale: Locale? = null private var carouselLocale: Locale? = null
private val animationScaleObserver: ContentObserver =
object : ContentObserver(null) {
override fun onChange(selfChange: Boolean) {
MediaPlayerData.players().forEach { it.updateAnimatorDurationScale() }
}
}
/** Whether the media card currently has the "expanded" layout */ /** Whether the media card currently has the "expanded" layout */
@VisibleForTesting @VisibleForTesting
var currentlyExpanded = true var currentlyExpanded = true
@@ -529,6 +540,12 @@ constructor(
listenForAnyStateToGoneKeyguardTransition(this) listenForAnyStateToGoneKeyguardTransition(this)
} }
} }
// Notifies all active players about animation scale changes.
globalSettings.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
animationScaleObserver
)
} }
private fun inflateSettingsButton() { private fun inflateSettingsButton() {

View File

@@ -34,7 +34,6 @@ import android.content.pm.PackageManager;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BlendMode; import android.graphics.BlendMode;
import android.graphics.Color; import android.graphics.Color;
@@ -252,13 +251,6 @@ public class MediaControlPanel {
private boolean mWasPlaying = false; private boolean mWasPlaying = false;
private boolean mButtonClicked = false; private boolean mButtonClicked = false;
private ContentObserver mAnimationScaleObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
updateAnimatorDurationScale();
}
};
/** /**
* Initialize a new control panel * Initialize a new control panel
* *
@@ -318,10 +310,6 @@ public class MediaControlPanel {
mFeatureFlags = featureFlags; mFeatureFlags = featureFlags;
mGlobalSettings = globalSettings; mGlobalSettings = globalSettings;
mGlobalSettings.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
mAnimationScaleObserver
);
updateAnimatorDurationScale(); updateAnimatorDurationScale();
} }
@@ -405,7 +393,10 @@ public class MediaControlPanel {
updateSeekBarVisibility(); updateSeekBarVisibility();
} }
private void updateAnimatorDurationScale() { /**
* Reloads animator duration scale.
*/
void updateAnimatorDurationScale() {
if (mSeekBarObserver != null) { if (mSeekBarObserver != null) {
mSeekBarObserver.setAnimationEnabled( mSeekBarObserver.setAnimationEnabled(
mGlobalSettings.getFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 1f) > 0f); mGlobalSettings.getFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 1f) > 0f);

View File

@@ -19,7 +19,9 @@ package com.android.systemui.media.controls.ui
import android.app.PendingIntent import android.app.PendingIntent
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.Configuration import android.content.res.Configuration
import android.database.ContentObserver
import android.os.LocaleList import android.os.LocaleList
import android.provider.Settings
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.testing.TestableLooper import android.testing.TestableLooper
import android.util.MathUtils.abs import android.util.MathUtils.abs
@@ -56,6 +58,7 @@ import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.eq
import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.time.FakeSystemClock
import java.util.Locale import java.util.Locale
import javax.inject.Provider import javax.inject.Provider
@@ -113,6 +116,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Mock lateinit var mediaFlags: MediaFlags @Mock lateinit var mediaFlags: MediaFlags
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock lateinit var globalSettings: GlobalSettings
private lateinit var transitionRepository: FakeKeyguardTransitionRepository private lateinit var transitionRepository: FakeKeyguardTransitionRepository
@Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener> @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
@Captor @Captor
@@ -120,6 +124,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener> @Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener>
@Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback> @Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
@Captor lateinit var hostStateCallback: ArgumentCaptor<MediaHostStatesManager.Callback> @Captor lateinit var hostStateCallback: ArgumentCaptor<MediaHostStatesManager.Callback>
@Captor lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
private val clock = FakeSystemClock() private val clock = FakeSystemClock()
private lateinit var mediaCarouselController: MediaCarouselController private lateinit var mediaCarouselController: MediaCarouselController
@@ -148,6 +153,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
mediaFlags, mediaFlags,
keyguardUpdateMonitor, keyguardUpdateMonitor,
KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope), KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope),
globalSettings
) )
verify(configurationController).addCallback(capture(configListener)) verify(configurationController).addCallback(capture(configListener))
verify(mediaDataManager).addListener(capture(listener)) verify(mediaDataManager).addListener(capture(listener))
@@ -160,6 +166,11 @@ class MediaCarouselControllerTest : SysuiTestCase() {
whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData) whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData)
whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false) whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
MediaPlayerData.clear() MediaPlayerData.clear()
verify(globalSettings)
.registerContentObserver(
eq(Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE)),
settingsObserverCaptor.capture()
)
} }
@Test @Test
@@ -873,6 +884,15 @@ class MediaCarouselControllerTest : SysuiTestCase() {
assertTrue(stateUpdated) assertTrue(stateUpdated)
} }
@Test
fun testAnimationScaleChanged_mediaControlPanelsNotified() {
MediaPlayerData.addMediaPlayer("key", DATA, panel, clock, isSsReactivated = false)
globalSettings.putFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 0f)
settingsObserverCaptor.value!!.onChange(false)
verify(panel).updateAnimatorDurationScale()
}
/** /**
* Helper method when a configuration change occurs. * Helper method when a configuration change occurs.
* *

View File

@@ -25,7 +25,6 @@ import android.content.Intent
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Configuration import android.content.res.Configuration
import android.database.ContentObserver
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
@@ -113,7 +112,6 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Captor
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.anyString import org.mockito.Mockito.anyString
import org.mockito.Mockito.mock import org.mockito.Mockito.mock
@@ -239,7 +237,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
this.set(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE, false) this.set(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE, false)
} }
@Mock private lateinit var globalSettings: GlobalSettings @Mock private lateinit var globalSettings: GlobalSettings
@Captor private lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
@JvmField @Rule val mockito = MockitoJUnit.rule() @JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -281,7 +278,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
lockscreenUserManager, lockscreenUserManager,
broadcastDialogController, broadcastDialogController,
fakeFeatureFlag, fakeFeatureFlag,
globalSettings, globalSettings
) { ) {
override fun loadAnimator( override fun loadAnimator(
animId: Int, animId: Int,
@@ -292,12 +289,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
} }
} }
verify(globalSettings)
.registerContentObserver(
eq(Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE)),
settingsObserverCaptor.capture()
)
initGutsViewHolderMocks() initGutsViewHolderMocks()
initMediaViewHolderMocks() initMediaViewHolderMocks()
@@ -986,7 +977,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
// When the setting changes, // When the setting changes,
globalSettings.putFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 0f) globalSettings.putFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 0f)
settingsObserverCaptor.value!!.onChange(false) player.updateAnimatorDurationScale()
// Then the seekbar is set to not animate // Then the seekbar is set to not animate
assertThat(seekBarObserver.animationEnabled).isFalse() assertThat(seekBarObserver.animationEnabled).isFalse()