Skip to content
Open
Changes from all commits
Commits
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 @@ -68,13 +68,43 @@ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request
return super.shouldOverrideUrlLoading(view, request);
}

/**
* One-pixel transparent placeholder used in place of a null favicon when
* forwarding {@link #onPageStarted(WebView, String, Bitmap)} to a delegate
* whose Kotlin signature declares favicon as a non-null {@code Bitmap}.
* Allocated lazily so there is no cost when the platform supplies a real
* favicon. See issue #490.
*/
private static volatile Bitmap sFaviconPlaceholder;

private static Bitmap faviconPlaceholder() {
Bitmap placeholder = sFaviconPlaceholder;
if (placeholder == null) {
synchronized (WebViewClientDelegate.class) {
placeholder = sFaviconPlaceholder;
if (placeholder == null) {
placeholder = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
sFaviconPlaceholder = placeholder;
}
}
}
return placeholder;
}
Comment on lines +78 to +92
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The placeholder bitmap is cached statically and the same instance is forwarded to external delegates. Because this instance escapes library ownership, a delegate could mutate or call recycle() on it, which would leave sFaviconPlaceholder in a bad state and potentially crash later calls. Consider either recreating the placeholder when placeholder.isRecycled() is true, or returning a fresh/copy placeholder per callback to avoid sharing a mutable/recyclable Bitmap instance with user code.

Copilot uses AI. Check for mistakes.

@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// Issue #490: WebView may deliver a null favicon at page-start. Kotlin
// delegates whose signature declares favicon as non-null Bitmap will
// crash at the synthetic Intrinsics.checkParameterIsNotNull check.
// Substitute a tiny transparent placeholder so non-null Kotlin
// signatures keep working; nullable signatures see no observable
// change beyond receiving a non-null bitmap.
Comment on lines +100 to +101
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment claims “nullable signatures see no observable change beyond receiving a non-null bitmap”, but receiving a non-null placeholder instead of null is an observable behavior change (callers may have been using null to mean “no favicon yet”). Please reword the comment to acknowledge this behavior change and/or describe how callers can detect the placeholder if needed.

Suggested change
// signatures keep working; nullable signatures see no observable
// change beyond receiving a non-null bitmap.
// signatures keep working. This is an observable change for nullable
// consumers because they receive the shared placeholder instead of
// null; callers that need to detect "no favicon yet" can compare the
// received Bitmap by identity with faviconPlaceholder().

Copilot uses AI. Check for mistakes.
Bitmap safeFavicon = favicon != null ? favicon : faviconPlaceholder();
if (mDelegate != null) {
mDelegate.onPageStarted(view, url, favicon);
mDelegate.onPageStarted(view, url, safeFavicon);
return;
}
super.onPageStarted(view, url, favicon);
super.onPageStarted(view, url, safeFavicon);
}

@Override
Expand Down
Loading