Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BigPictureIconManager.kt +15 −16 Original line number Diff line number Diff line Loading @@ -89,6 +89,7 @@ constructor( this.lastLoadingJob?.cancel() this.lastLoadingJob = when { skipLazyLoading(state.icon) -> null state is Empty && shown -> state.icon?.let(::startLoadingJob) state is PlaceHolder && shown -> startLoadingJob(state.icon) state is FullImage && !shown -> Loading Loading @@ -119,12 +120,6 @@ constructor( return Runnable {} } if (displayedState.iconSameAs(icon)) { // We're already handling this icon, nothing to do here. log("skipping updateIcon for consumer:$drawableConsumer with icon:$icon") return Runnable {} } this.drawableConsumer = drawableConsumer this.displayedState = Empty(icon) this.lastLoadingJob?.cancel() Loading @@ -144,7 +139,7 @@ constructor( private fun loadImageOrPlaceHolderSync(icon: Icon?): Drawable? { icon ?: return null if (viewShown) { if (viewShown || skipLazyLoading(icon)) { return loadImageSync(icon) } Loading Loading @@ -228,6 +223,19 @@ constructor( } ) /** * We don't support lazy-loading or set placeholders for bitmap and data based icons, because * they gonna stay in memory anyways. */ private fun skipLazyLoading(icon: Icon?): Boolean = when (icon?.type) { Icon.TYPE_BITMAP, Icon.TYPE_ADAPTIVE_BITMAP, Icon.TYPE_DATA, null -> true else -> false } private fun log(msg: String) { if (DEBUG) { Log.d(TAG, "$msg state=${getDebugString()}") Loading @@ -242,15 +250,6 @@ constructor( data class PlaceHolder(override val icon: Icon, val drawableSize: Size) : DrawableState(icon) data class FullImage(override val icon: Icon, val drawableSize: Size) : DrawableState(icon) fun iconSameAs(other: Icon?): Boolean { val displayedIcon = icon return when { displayedIcon == null && other == null -> true displayedIcon != null && other != null -> displayedIcon.sameAs(other) else -> false } } } } Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt +89 −8 Original line number Diff line number Diff line Loading @@ -70,7 +70,7 @@ class BigPictureIconManagerTest : SysuiTestCase() { } private val unsupportedIcon by lazy { Icon.createWithBitmap( BitmapFactory.decodeResource(context.resources, R.drawable.dessert_zombiegingerbread) BitmapFactory.decodeResource(context.resources, R.drawable.dessert_donutburger) ) } private val invalidIcon by lazy { Icon.createWithContentUri(Uri.parse("this.is/broken")) } Loading Loading @@ -100,7 +100,7 @@ class BigPictureIconManagerTest : SysuiTestCase() { } @Test fun onIconUpdated_notSupportedType_fullImageLoaded() = fun onIconUpdated_unsupportedType_fullImageLoaded() = testScope.runTest { // WHEN update with an unsupported icon iconManager.updateIcon(mockConsumer, unsupportedIcon).run() Loading @@ -111,6 +111,16 @@ class BigPictureIconManagerTest : SysuiTestCase() { assertSize(drawableCaptor.value) } @Test fun onIconUpdated_withNull_drawableIsNull() = testScope.runTest { // WHEN update with null iconManager.updateIcon(mockConsumer, null).run() // THEN consumer is updated with null verify(mockConsumer).setImageDrawable(null) } @Test fun onIconUpdated_invalidIcon_drawableIsNull() = testScope.runTest { Loading Loading @@ -152,6 +162,43 @@ class BigPictureIconManagerTest : SysuiTestCase() { assertSize(drawableCaptor.value) } @Test fun onIconUpdated_iconAlreadySetForTheSameIcon_loadsIconAgain() = testScope.runTest { // GIVEN an icon is set iconManager.updateIcon(mockConsumer, supportedIcon).run() // AND the view is shown iconManager.onViewShown(true) runCurrent() reset(mockConsumer) // WHEN the icon is set again iconManager.updateIcon(mockConsumer, supportedIcon).run() // THEN consumer is updated with the new image verify(mockConsumer).setImageDrawable(drawableCaptor.capture()) assertIsFullImage(drawableCaptor.value) assertSize(drawableCaptor.value) } @Test fun onIconUpdated_iconAlreadySetForUnsupportedIcon_loadsNewIcon() = testScope.runTest { // GIVEN an unsupported icon is set iconManager.updateIcon(mockConsumer, unsupportedIcon).run() // AND the view is shown iconManager.onViewShown(true) runCurrent() reset(mockConsumer) // WHEN a new icon is set iconManager.updateIcon(mockConsumer, supportedIcon).run() // THEN consumer is updated with the new image verify(mockConsumer).setImageDrawable(drawableCaptor.capture()) assertIsFullImage(drawableCaptor.value) assertSize(drawableCaptor.value) } @Test fun onIconUpdated_supportedTypeButTooWide_resizedPlaceholderLoaded() = testScope.runTest { Loading Loading @@ -249,12 +296,10 @@ class BigPictureIconManagerTest : SysuiTestCase() { verifyZeroInteractions(mockConsumer) } // nice to have tests @Test fun onViewShown_fullImageLoaded_nothingHappens() = fun onViewShown_unsupportedIconLoaded_nothingHappens() = testScope.runTest { // GIVEN full image is showing // GIVEN full image is showing for an unsupported icon iconManager.updateIcon(mockConsumer, unsupportedIcon).run() reset(mockConsumer) Loading @@ -266,11 +311,46 @@ class BigPictureIconManagerTest : SysuiTestCase() { verifyZeroInteractions(mockConsumer) } @Test fun onViewShown_nullSetForIcon_nothingHappens() = testScope.runTest { // GIVEN null is set for the icon iconManager.updateIcon(mockConsumer, null).run() reset(mockConsumer) // WHEN the view is shown iconManager.onViewShown(true) runCurrent() // THEN nothing happens verifyZeroInteractions(mockConsumer) } @Test fun onViewHidden_unsupportedIconLoadedAndViewIsShown_nothingHappens() = testScope.runTest { // GIVEN full image is showing for an unsupported icon iconManager.updateIcon(mockConsumer, unsupportedIcon).run() // AND the view is shown iconManager.onViewShown(true) runCurrent() reset(mockConsumer) // WHEN the view goes off the screen iconManager.onViewShown(false) // AND we wait a bit advanceTimeBy(FREE_IMAGE_DELAY_MS) runCurrent() // THEN nothing happens verifyZeroInteractions(mockConsumer) } @Test fun onViewHidden_placeholderShowing_nothingHappens() = testScope.runTest { // GIVEN placeholder image is showing iconManager.updateIcon(mockConsumer, unsupportedIcon).run() iconManager.updateIcon(mockConsumer, supportedIcon).run() reset(mockConsumer) // WHEN the view is hidden Loading @@ -296,6 +376,7 @@ class BigPictureIconManagerTest : SysuiTestCase() { iconManager.onViewShown(true) runCurrent() // THEN nothing happens verifyZeroInteractions(mockConsumer) } Loading @@ -303,7 +384,7 @@ class BigPictureIconManagerTest : SysuiTestCase() { fun onViewHidden_alreadyHidden_nothingHappens() = testScope.runTest { // GIVEN placeholder image is showing and the view is hidden iconManager.updateIcon(mockConsumer, unsupportedIcon).run() iconManager.updateIcon(mockConsumer, supportedIcon).run() iconManager.onViewShown(false) advanceTimeBy(FREE_IMAGE_DELAY_MS) runCurrent() Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BigPictureIconManager.kt +15 −16 Original line number Diff line number Diff line Loading @@ -89,6 +89,7 @@ constructor( this.lastLoadingJob?.cancel() this.lastLoadingJob = when { skipLazyLoading(state.icon) -> null state is Empty && shown -> state.icon?.let(::startLoadingJob) state is PlaceHolder && shown -> startLoadingJob(state.icon) state is FullImage && !shown -> Loading Loading @@ -119,12 +120,6 @@ constructor( return Runnable {} } if (displayedState.iconSameAs(icon)) { // We're already handling this icon, nothing to do here. log("skipping updateIcon for consumer:$drawableConsumer with icon:$icon") return Runnable {} } this.drawableConsumer = drawableConsumer this.displayedState = Empty(icon) this.lastLoadingJob?.cancel() Loading @@ -144,7 +139,7 @@ constructor( private fun loadImageOrPlaceHolderSync(icon: Icon?): Drawable? { icon ?: return null if (viewShown) { if (viewShown || skipLazyLoading(icon)) { return loadImageSync(icon) } Loading Loading @@ -228,6 +223,19 @@ constructor( } ) /** * We don't support lazy-loading or set placeholders for bitmap and data based icons, because * they gonna stay in memory anyways. */ private fun skipLazyLoading(icon: Icon?): Boolean = when (icon?.type) { Icon.TYPE_BITMAP, Icon.TYPE_ADAPTIVE_BITMAP, Icon.TYPE_DATA, null -> true else -> false } private fun log(msg: String) { if (DEBUG) { Log.d(TAG, "$msg state=${getDebugString()}") Loading @@ -242,15 +250,6 @@ constructor( data class PlaceHolder(override val icon: Icon, val drawableSize: Size) : DrawableState(icon) data class FullImage(override val icon: Icon, val drawableSize: Size) : DrawableState(icon) fun iconSameAs(other: Icon?): Boolean { val displayedIcon = icon return when { displayedIcon == null && other == null -> true displayedIcon != null && other != null -> displayedIcon.sameAs(other) else -> false } } } } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt +89 −8 Original line number Diff line number Diff line Loading @@ -70,7 +70,7 @@ class BigPictureIconManagerTest : SysuiTestCase() { } private val unsupportedIcon by lazy { Icon.createWithBitmap( BitmapFactory.decodeResource(context.resources, R.drawable.dessert_zombiegingerbread) BitmapFactory.decodeResource(context.resources, R.drawable.dessert_donutburger) ) } private val invalidIcon by lazy { Icon.createWithContentUri(Uri.parse("this.is/broken")) } Loading Loading @@ -100,7 +100,7 @@ class BigPictureIconManagerTest : SysuiTestCase() { } @Test fun onIconUpdated_notSupportedType_fullImageLoaded() = fun onIconUpdated_unsupportedType_fullImageLoaded() = testScope.runTest { // WHEN update with an unsupported icon iconManager.updateIcon(mockConsumer, unsupportedIcon).run() Loading @@ -111,6 +111,16 @@ class BigPictureIconManagerTest : SysuiTestCase() { assertSize(drawableCaptor.value) } @Test fun onIconUpdated_withNull_drawableIsNull() = testScope.runTest { // WHEN update with null iconManager.updateIcon(mockConsumer, null).run() // THEN consumer is updated with null verify(mockConsumer).setImageDrawable(null) } @Test fun onIconUpdated_invalidIcon_drawableIsNull() = testScope.runTest { Loading Loading @@ -152,6 +162,43 @@ class BigPictureIconManagerTest : SysuiTestCase() { assertSize(drawableCaptor.value) } @Test fun onIconUpdated_iconAlreadySetForTheSameIcon_loadsIconAgain() = testScope.runTest { // GIVEN an icon is set iconManager.updateIcon(mockConsumer, supportedIcon).run() // AND the view is shown iconManager.onViewShown(true) runCurrent() reset(mockConsumer) // WHEN the icon is set again iconManager.updateIcon(mockConsumer, supportedIcon).run() // THEN consumer is updated with the new image verify(mockConsumer).setImageDrawable(drawableCaptor.capture()) assertIsFullImage(drawableCaptor.value) assertSize(drawableCaptor.value) } @Test fun onIconUpdated_iconAlreadySetForUnsupportedIcon_loadsNewIcon() = testScope.runTest { // GIVEN an unsupported icon is set iconManager.updateIcon(mockConsumer, unsupportedIcon).run() // AND the view is shown iconManager.onViewShown(true) runCurrent() reset(mockConsumer) // WHEN a new icon is set iconManager.updateIcon(mockConsumer, supportedIcon).run() // THEN consumer is updated with the new image verify(mockConsumer).setImageDrawable(drawableCaptor.capture()) assertIsFullImage(drawableCaptor.value) assertSize(drawableCaptor.value) } @Test fun onIconUpdated_supportedTypeButTooWide_resizedPlaceholderLoaded() = testScope.runTest { Loading Loading @@ -249,12 +296,10 @@ class BigPictureIconManagerTest : SysuiTestCase() { verifyZeroInteractions(mockConsumer) } // nice to have tests @Test fun onViewShown_fullImageLoaded_nothingHappens() = fun onViewShown_unsupportedIconLoaded_nothingHappens() = testScope.runTest { // GIVEN full image is showing // GIVEN full image is showing for an unsupported icon iconManager.updateIcon(mockConsumer, unsupportedIcon).run() reset(mockConsumer) Loading @@ -266,11 +311,46 @@ class BigPictureIconManagerTest : SysuiTestCase() { verifyZeroInteractions(mockConsumer) } @Test fun onViewShown_nullSetForIcon_nothingHappens() = testScope.runTest { // GIVEN null is set for the icon iconManager.updateIcon(mockConsumer, null).run() reset(mockConsumer) // WHEN the view is shown iconManager.onViewShown(true) runCurrent() // THEN nothing happens verifyZeroInteractions(mockConsumer) } @Test fun onViewHidden_unsupportedIconLoadedAndViewIsShown_nothingHappens() = testScope.runTest { // GIVEN full image is showing for an unsupported icon iconManager.updateIcon(mockConsumer, unsupportedIcon).run() // AND the view is shown iconManager.onViewShown(true) runCurrent() reset(mockConsumer) // WHEN the view goes off the screen iconManager.onViewShown(false) // AND we wait a bit advanceTimeBy(FREE_IMAGE_DELAY_MS) runCurrent() // THEN nothing happens verifyZeroInteractions(mockConsumer) } @Test fun onViewHidden_placeholderShowing_nothingHappens() = testScope.runTest { // GIVEN placeholder image is showing iconManager.updateIcon(mockConsumer, unsupportedIcon).run() iconManager.updateIcon(mockConsumer, supportedIcon).run() reset(mockConsumer) // WHEN the view is hidden Loading @@ -296,6 +376,7 @@ class BigPictureIconManagerTest : SysuiTestCase() { iconManager.onViewShown(true) runCurrent() // THEN nothing happens verifyZeroInteractions(mockConsumer) } Loading @@ -303,7 +384,7 @@ class BigPictureIconManagerTest : SysuiTestCase() { fun onViewHidden_alreadyHidden_nothingHappens() = testScope.runTest { // GIVEN placeholder image is showing and the view is hidden iconManager.updateIcon(mockConsumer, unsupportedIcon).run() iconManager.updateIcon(mockConsumer, supportedIcon).run() iconManager.onViewShown(false) advanceTimeBy(FREE_IMAGE_DELAY_MS) runCurrent() Loading