diff --git a/.gitignore b/.gitignore index 598def77e641..daafde085962 100644 --- a/.gitignore +++ b/.gitignore @@ -388,3 +388,6 @@ temp # TypeScript source map files (generated artifacts) # Note: CSS map files in templates (e.g., bootstrap) are intentionally tracked *.js.map + +# Gradle build reports +src/Core/AndroidNative/build/reports/ diff --git a/src/Core/AndroidNative/build/reports/problems/problems-report.html b/src/Core/AndroidNative/build/reports/problems/problems-report.html deleted file mode 100644 index 28c86c49448d..000000000000 --- a/src/Core/AndroidNative/build/reports/problems/problems-report.html +++ /dev/null @@ -1,663 +0,0 @@ - - - - - - - - - - - - - Gradle Configuration Cache - - - -
- -
- Loading... -
- - - - - - diff --git a/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java b/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java index 10f724424e45..2601e0b5f351 100644 --- a/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java +++ b/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java @@ -2,6 +2,7 @@ import android.app.Activity; import android.content.Context; +import android.content.ContextWrapper; import android.content.res.ColorStateList; import android.graphics.BlendMode; import android.graphics.BlendModeColorFilter; @@ -363,6 +364,10 @@ public static void loadImageFromFont(ImageView imageView, @ColorInt int color, S } public static void loadImageFromFile(Context context, String file, ImageLoaderCallback callback) { + if (isContextDestroyed(context)) { + callback.onComplete(false, null, null); + return; + } RequestBuilder builder = Glide .with(context) .load(file); @@ -370,6 +375,10 @@ public static void loadImageFromFile(Context context, String file, ImageLoaderCa } public static void loadImageFromUri(Context context, String uri, boolean cachingEnabled, ImageLoaderCallback callback) { + if (isContextDestroyed(context)) { + callback.onComplete(false, null, null); + return; + } Uri androidUri = Uri.parse(uri); if (androidUri == null) { callback.onComplete(false, null, null); @@ -382,6 +391,10 @@ public static void loadImageFromUri(Context context, String uri, boolean caching } public static void loadImageFromStream(Context context, InputStream inputStream, ImageLoaderCallback callback) { + if (isContextDestroyed(context)) { + callback.onComplete(false, null, null); + return; + } RequestBuilder builder = Glide .with(context) .load(inputStream); @@ -389,6 +402,10 @@ public static void loadImageFromStream(Context context, InputStream inputStream, } public static void loadImageFromFont(Context context, @ColorInt int color, String glyph, Typeface typeface, float textSize, ImageLoaderCallback callback) { + if (isContextDestroyed(context)) { + callback.onComplete(false, null, null); + return; + } FontModel fontModel = new FontModel(color, glyph, textSize, typeface); RequestBuilder builder = Glide .with(context) @@ -704,4 +721,39 @@ public static boolean isImageViewCenterCrop(@NonNull ImageView imageView) { public static void setClipBounds(@NonNull View view, int left, int top, int right, int bottom) { view.setClipBounds(new Rect(left, top, right, bottom)); } + + /** + * Checks if the provided context's underlying Activity is destroyed or finishing. + * This is used to prevent Glide crashes when attempting to load images after activity destruction. + * @param context The context to check + * @return true if the context is destroyed, false otherwise + */ + public static boolean isContextDestroyed(Context context) { + Activity activity = getActivity(context); + if (activity != null) { + if (activity.isFinishing() || activity.isDestroyed()) { + return true; + } + } + return false; + } + + /** + * Extracts the Activity from a Context, handling ContextWrapper chains. + * @param context The context to extract the Activity from + * @return The Activity if found, null otherwise + */ + private static Activity getActivity(Context context) { + if (context == null) { + return null; + } + if (context instanceof Activity) { + return (Activity) context; + } + if (context instanceof ContextWrapper) { + Context baseContext = ((ContextWrapper) context).getBaseContext(); + return getActivity(baseContext); + } + return null; + } } diff --git a/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/glide/MauiCustomTarget.java b/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/glide/MauiCustomTarget.java index 21129ce2d40a..2d75dad75dd4 100644 --- a/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/glide/MauiCustomTarget.java +++ b/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/glide/MauiCustomTarget.java @@ -1,8 +1,6 @@ package com.microsoft.maui.glide; -import android.app.Activity; import android.content.Context; -import android.content.ContextWrapper; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; @@ -16,6 +14,7 @@ import com.bumptech.glide.request.transition.Transition; import com.microsoft.maui.ImageLoaderCallback; +import com.microsoft.maui.PlatformInterop; import com.microsoft.maui.PlatformLogger; import com.microsoft.maui.glide.MauiTarget; @@ -82,35 +81,11 @@ private void post(Runnable runnable) { handler.post(runnable); } - private static boolean isContextDestroyed(Context context) { - Activity activity = getActivity(context); - if (activity != null) { - if (activity.isFinishing() || activity.isDestroyed()) { - return true; - } - } - return false; - } - - private static Activity getActivity(Context context) { - if (context == null) { - return null; - } - if (context instanceof Activity) { - return (Activity) context; - } - if (context instanceof ContextWrapper) { - Context baseContext = ((ContextWrapper) context).getBaseContext(); - return getActivity(baseContext); - } - return null; - } - private void clear() { // TODO: it looks like no one is really disposing the result on C# side // we must fix it there to release the Glide cache entry properly post(() -> { - if (isContextDestroyed(context)) { + if (PlatformInterop.isContextDestroyed(context)) { if (logger.isVerboseLoggable) { logger.v("clear() skipped - context destroyed: " + resourceLogIdentifier); }