File: Android\Extensions\ImageViewExtensions.cs
Web Access
Project: src\src\Compatibility\Core\src\Compatibility.csproj (Microsoft.Maui.Controls.Compatibility)
using System.Threading.Tasks;
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Microsoft.Maui.Controls.Internals;
using AImageView = Android.Widget.ImageView;
 
namespace Microsoft.Maui.Controls.Compatibility.Platform.Android
{
	internal static class ImageViewExtensions
	{
		public static Task UpdateBitmap(this AImageView imageView, IImageElement newView, IImageElement previousView) =>
			imageView.UpdateBitmap(newView, previousView, null, null);
 
		public static Task UpdateBitmap(this AImageView imageView, ImageSource newImageSource, ImageSource previousImageSourc) =>
			imageView.UpdateBitmap(null, null, newImageSource, previousImageSourc);
 
		static async Task UpdateBitmap(
			this AImageView imageView,
			IImageElement newView,
			IImageElement previousView,
			ImageSource newImageSource,
			ImageSource previousImageSource)
		{
 
			IImageController imageController = newView as IImageController;
			newImageSource = newImageSource ?? newView?.Source;
			previousImageSource = previousImageSource ?? previousView?.Source;
 
			if (imageView.IsDisposed())
				return;
 
			if (newImageSource != null && Equals(previousImageSource, newImageSource))
				return;
 
			imageController?.SetIsLoading(true);
 
			(imageView as IImageRendererController)?.SkipInvalidate();
			imageView.Reset();
			imageView.SetImageResource(global::Android.Resource.Color.Transparent);
 
			try
			{
				if (newImageSource != null)
				{
					// all this animation code will go away if/once we pull in GlideX
					IFormsAnimationDrawable animation = null;
 
					if (imageController != null && imageController.GetLoadAsAnimation())
					{
						var animationHandler = Registrar.Registered.GetHandlerForObject<IAnimationSourceHandler>(newImageSource);
						if (animationHandler != null)
							animation = await animationHandler.LoadImageAnimationAsync(newImageSource, imageView.Context);
					}
 
					if (animation == null)
					{
						var imageViewHandler = Registrar.Registered.GetHandlerForObject<IImageViewHandler>(newImageSource);
						if (imageViewHandler != null)
						{
							await imageViewHandler.LoadImageAsync(newImageSource, imageView);
						}
						else
						{
							using (var drawable = await imageView.Context.GetFormsDrawableAsync(newImageSource))
							{
								// only set the image if we are still on the same one
								if (!imageView.IsDisposed() && SourceIsNotChanged(newView, newImageSource))
									imageView.SetImageDrawable(drawable);
							}
						}
					}
					else
					{
						if (!imageView.IsDisposed() && SourceIsNotChanged(newView, newImageSource))
							imageView.SetImageDrawable(animation.ImageDrawable);
						else
						{
							animation?.Reset();
							animation?.Dispose();
						}
					}
				}
				else
				{
					imageView.SetImageBitmap(null);
				}
			}
			finally
			{
				// only mark as finished if we are still working on the same image
				if (SourceIsNotChanged(newView, newImageSource))
				{
					imageController?.SetIsLoading(false);
					imageController?.PlatformSizeChanged();
				}
			}
 
 
			bool SourceIsNotChanged(IImageElement imageElement, ImageSource imageSource)
			{
				return (imageElement != null) ? imageElement.Source == imageSource : true;
			}
		}
 
		internal static void Reset(this IFormsAnimationDrawable formsAnimation)
		{
			if (formsAnimation is FormsAnimationDrawable animation)
			{
				if (!animation.IsDisposed())
				{
					animation.Stop();
					int frameCount = animation.NumberOfFrames;
					for (int i = 0; i < frameCount; i++)
					{
						var currentFrame = animation.GetFrame(i);
						if (currentFrame is BitmapDrawable bitmapDrawable)
						{
							var bitmap = bitmapDrawable.Bitmap;
							if (bitmap != null)
							{
								if (!bitmap.IsRecycled)
								{
									bitmap.Recycle();
								}
								bitmap.Dispose();
								bitmap = null;
							}
							bitmapDrawable.Dispose();
							bitmapDrawable = null;
						}
						currentFrame = null;
					}
					animation = null;
				}
			}
		}
 
		public static void Reset(this AImageView imageView)
		{
			if (!imageView.IsDisposed())
			{
				if (imageView.Drawable is FormsAnimationDrawable animation)
				{
					imageView.SetImageDrawable(null);
					animation.Reset();
				}
 
				imageView.SetImageResource(global::Android.Resource.Color.Transparent);
			}
		}
 
		internal static async void SetImage(this AImageView image, ImageSource source, Context context)
		{
			image.SetImageDrawable(await context.GetFormsDrawableAsync(source));
		}
	}
}