Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
17e8a5e
Initial plan
Copilot May 25, 2026
7a6690f
Fix Android large image loading by capping decode size
Copilot May 25, 2026
d647ccf
Refine oversized image cap guard and test clarity
Copilot May 25, 2026
7702c62
Rename oversized image test margin constant for clarity
Copilot May 25, 2026
fe546f5
Address AI feedback on Android image sizing behavior
Copilot Jul 10, 2026
8a0483e
Address review feedback for #35606
Copilot Jul 12, 2026
f129408
Constrain ImageView stream downsampling for #35606
Copilot Jul 12, 2026
efbb3c8
Preserve Android resource ImageView fast path for #35606
Copilot Jul 12, 2026
bcf3853
Bound Android ImageView stream decodes for #35606
Copilot Jul 12, 2026
f93775c
Address image source review coverage for #35606
Copilot Jul 12, 2026
a33b70b
Return null instead of throwing on failed Android resource drawable l…
Copilot Jul 14, 2026
a36a181
Route Android resource ImageView loads through bounded Glide path (#3…
Copilot Jul 14, 2026
14b21e0
Use target-bounded Android ImageView decode scaling (#35606)
Copilot Jul 14, 2026
6e63183
Preserve Android ImageView sizing in bounded decodes (#35606)
Copilot Jul 14, 2026
fe7f429
Cap Android decode bounds consistently across orientations (#35606)
Copilot Jul 14, 2026
424f89d
Restore per-dimension Android display decode caps (#35606)
Copilot Jul 14, 2026
ecdab27
Update ImageHandlerTests for Glide-based Android app-resource loading
Copilot Jul 15, 2026
db0d955
Match downsample strategy to ImageView ScaleType for CenterCrop
Copilot Jul 17, 2026
54456ba
Extend Android decode-size cap to Aspect.Fill and Aspect.Center
Copilot Jul 17, 2026
db059b8
[Android] Observe cancellation after async Glide image load
Copilot Jul 17, 2026
117fdb3
[Android] Propagate image-load cancellation and bound cover/fill deco…
Copilot Jul 18, 2026
bf0ade8
[Android] Display-bound the default FitCenter image decode path
Copilot Jul 19, 2026
8b4f94f
[Android] Bound thumbnail decodes to view size and fix canceled-null …
Copilot Jul 19, 2026
e6dd195
[Android] Use file:// scheme in URI image-source device tests
Copilot Jul 19, 2026
383217e
Cover-decode AspectFill/Fill via display-bounded fill strategy
Copilot Jul 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,41 @@ private static void load(RequestBuilder<Drawable> builder, Context context, bool
prepare(builder, target, cachingEnabled, callback);
}

private static RequestBuilder<Drawable> limitToDisplaySize(RequestBuilder<Drawable> builder, Context context) {
if (context == null) {
return builder;
}

DisplayMetrics metrics = context.getResources().getDisplayMetrics();
if (metrics == null) {
return builder;
}

int width = metrics.widthPixels;
int height = metrics.heightPixels;
if (width <= 0 || height <= 0) {
return builder;
}

return builder.override(width, height);
Comment thread
kubaflo marked this conversation as resolved.
Outdated
}

public static void loadImageFromFile(ImageView imageView, String file, ImageLoaderCallback callback) {
RequestBuilder<Drawable> builder = Glide
.with(imageView)
.load(file);
builder = limitToDisplaySize(builder, imageView.getContext());
Comment thread
kubaflo marked this conversation as resolved.
Outdated
loadInto(builder, imageView, true, callback, file);
}

public static void loadImageFromResource(ImageView imageView, int resourceId, ImageLoaderCallback callback) {
RequestBuilder<Drawable> builder = Glide
.with(imageView)
.load(resourceId);
builder = limitToDisplaySize(builder, imageView.getContext());
loadInto(builder, imageView, true, callback, resourceId);
}

public static void loadImageFromUri(ImageView imageView, String uri, boolean cachingEnabled, ImageLoaderCallback callback) {
Uri androidUri = Uri.parse(uri);
if (androidUri == null) {
Expand All @@ -352,14 +380,15 @@ public static void loadImageFromUri(ImageView imageView, String uri, boolean cac
RequestBuilder<Drawable> builder = Glide
.with(imageView)
.load(androidUri);
builder = limitToDisplaySize(builder, imageView.getContext());
loadInto(builder, imageView, cachingEnabled, callback, androidUri);
}

public static void loadImageFromStream(ImageView imageView, InputStream inputStream, ImageLoaderCallback callback) {
RequestBuilder<Drawable> builder = Glide
.with(imageView)
.load(inputStream)
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
.load(inputStream);
builder = limitToDisplaySize(builder, imageView.getContext());
loadInto(builder, imageView, false, callback, inputStream);
}

Expand All @@ -380,9 +409,22 @@ public static void loadImageFromFile(Context context, String file, ImageLoaderCa
RequestBuilder<Drawable> builder = Glide
.with(context)
.load(file);
builder = limitToDisplaySize(builder, context);
load(builder, context, true, callback, file);
}

public static void loadImageFromResource(Context context, int resourceId, ImageLoaderCallback callback) {
if (isContextDestroyed(context)) {
callback.onComplete(false, null, null);
return;
}
RequestBuilder<Drawable> builder = Glide
.with(context)
.load(resourceId);
builder = limitToDisplaySize(builder, context);
load(builder, context, true, callback, resourceId);
}

public static void loadImageFromUri(Context context, String uri, boolean cachingEnabled, ImageLoaderCallback callback) {
if (isContextDestroyed(context)) {
callback.onComplete(false, null, null);
Expand All @@ -396,6 +438,7 @@ public static void loadImageFromUri(Context context, String uri, boolean caching
RequestBuilder<Drawable> builder = Glide
.with(context)
.load(androidUri);
builder = limitToDisplaySize(builder, context);
load(builder, context, cachingEnabled, callback, androidUri);
}

Expand All @@ -406,8 +449,8 @@ public static void loadImageFromStream(Context context, InputStream inputStream,
}
RequestBuilder<Drawable> builder = Glide
.with(context)
.load(inputStream)
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
.load(inputStream);
builder = limitToDisplaySize(builder, context);
load(builder, context, false, callback, inputStream);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ public partial class FileImageSourceService
var id = imageView.Context?.GetDrawableId(file) ?? -1;
if (id > 0)
{
imageView.SetImageResource(id);
return Task.FromResult<IImageSourceServiceResult?>(new ImageSourceServiceLoadResult());
var resourceCallback = new ImageLoaderCallback();
PlatformInterop.LoadImageFromResource(imageView, id, resourceCallback);
Comment thread
kubaflo marked this conversation as resolved.
Comment on lines 27 to +31
return resourceCallback.Result;
}
}

Expand Down Expand Up @@ -62,9 +63,9 @@ public partial class FileImageSourceService
var id = context?.GetDrawableId(file) ?? -1;
if (id > 0)
{
var d = context?.GetDrawable(id);
if (d is not null)
return Task.FromResult<IImageSourceServiceResult<Drawable>?>(new ImageSourceServiceResult(d));
var resourceCallback = new ImageLoaderResultCallback();
PlatformInterop.LoadImageFromResource(context, id, resourceCallback);
return resourceCallback.Result;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace Microsoft.Maui.DeviceTests
{
public partial class StreamImageSourceServiceTests
{
const int OversizePixelMargin = 500;

[Theory]
[InlineData(typeof(FileImageSourceStub))]
[InlineData(typeof(FontImageSourceStub))]
Expand Down Expand Up @@ -44,5 +46,24 @@ public async Task GetDrawableAsync(string colorHex)

await bitmap.AssertContainsColor(expectedColor).ConfigureAwait(false);
}

[Fact]
public async Task GetDrawableAsyncLimitsLargeStreamToDisplaySize()
{
var metrics = MauiProgram.DefaultContext?.Resources?.DisplayMetrics;
Assert.NotNull(metrics);

var service = new StreamImageSourceService();
var expectedColor = Color.FromArgb("#FF0000").ToPlatform();
var sourceWidth = metrics.WidthPixels + OversizePixelMargin;
var sourceHeight = metrics.HeightPixels + OversizePixelMargin;
var imageSource = new StreamImageSourceStub(CreateBitmapStream(sourceWidth, sourceHeight, expectedColor));
Comment thread
kubaflo marked this conversation as resolved.

using var result = await service.GetDrawableAsync(imageSource, MauiProgram.DefaultContext);
var bitmapDrawable = Assert.IsType<BitmapDrawable>(result.Value);

Assert.True(bitmapDrawable.Bitmap.Width <= metrics.WidthPixels);
Assert.True(bitmapDrawable.Bitmap.Height <= metrics.HeightPixels);
}
}
}
Loading