Commit b4b8a01e authored by Clark DuVall's avatar Clark DuVall Committed by Commit Bot

[WebLayer] Load resources correctly for standalone WebView APK

This fixes resources loading, and allows WebLayer to work with the
standalone WebView APK, which previously would crash with a
Resources$NotFoundException exception.

Adds a run_weblayer_shell_webview build target for testing with
standalone WebView.

Change-Id: If1063efdfbf462ccf36bc54f796d3b934a456274
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1854204Reviewed-by: default avatarRichard Coles <torne@chromium.org>
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706086}
parent 55f96bee
......@@ -5,6 +5,11 @@
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
android_resources("weblayer_resources") {
resource_dirs = []
custom_package = "org.chromium.weblayer_private"
}
android_library("java") {
java_files = [
"org/chromium/weblayer_private/BrowserControllerImpl.java",
......@@ -25,6 +30,7 @@ android_library("java") {
deps = [
":client_java",
":weblayer_resources",
"//base:base_java",
"//base:jni_java",
"//content/public/android:content_java",
......
......@@ -52,8 +52,12 @@ public final class WebLayerImpl extends IWebLayer.Stub {
}
@Override
public void initAndLoadAsync(
IObjectWrapper webLayerContextWrapper, IObjectWrapper loadedCallbackWrapper) {
public void initAndLoadAsync(IObjectWrapper webLayerContextWrapper,
IObjectWrapper loadedCallbackWrapper, int resourcesPackageId) {
// TODO: The call to onResourcesLoaded() can be slow, we may need to parallelize this with
// other expensive startup tasks.
R.onResourcesLoaded(resourcesPackageId);
Context context = ObjectWrapper.unwrap(webLayerContextWrapper, Context.class);
ContextUtils.initApplicationContext(context);
ResourceBundle.setNoAvailableLocalePaks();
......
......@@ -16,7 +16,8 @@ interface IWebLayer {
// when load completes. |webLayerContext| is a Context that refers to the
// WebLayer implementation.
void initAndLoadAsync(in IObjectWrapper webLayerContext,
in IObjectWrapper loadedCallback) = 1;
in IObjectWrapper loadedCallback,
int resourcesPackageId) = 1;
// Blocks until loading has completed.
void loadSync() = 2;
......
......@@ -10,7 +10,6 @@ import android.content.ContextWrapper;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
......@@ -48,26 +47,9 @@ public final class WebLayer {
* Loads the WebLayer implementation and returns the IWebLayer. This does *not* trigger the
* implementation to start.
*/
private static IWebLayer connectToWebLayerImplementation(Context application)
private static IWebLayer connectToWebLayerImplementation(Context remoteContext)
throws UnsupportedVersionException {
try {
// TODO: Make asset loading work on L, where WebViewDelegate doesn't exist.
// WebViewDelegate.addWebViewAssetPath() accesses the currently loaded package info from
// WebViewFactory, so we have to fake it.
PackageInfo implPackageInfo = application.getPackageManager().getPackageInfo(
getImplPackageName(application), PackageManager.GET_META_DATA);
Field packageInfo = WebViewFactory.class.getDeclaredField("sPackageInfo");
packageInfo.setAccessible(true);
packageInfo.set(null, implPackageInfo);
// TODO(torne): Figure out how to load assets for production.
// Load assets using the WebViewDelegate.
Constructor constructor = WebViewDelegate.class.getDeclaredConstructor();
constructor.setAccessible(true);
WebViewDelegate delegate = (WebViewDelegate) constructor.newInstance();
delegate.addWebViewAssetPath(application);
Context remoteContext = createRemoteContext(application);
Class webLayerClass = remoteContext.getClassLoader().loadClass(
"org.chromium.weblayer_private.WebLayerImpl");
......@@ -86,6 +68,35 @@ public final class WebLayer {
}
}
/**
* Loads assets for WebLayer and returns the package ID to use when calling
* R.onResourcesLoaded().
*/
private static int loadAssets(Context appContext, Context remoteContext) {
WebViewDelegate delegate;
PackageInfo implPackageInfo;
try {
// TODO: Make asset loading work on L, where WebViewDelegate doesn't exist.
// WebViewDelegate.addWebViewAssetPath() accesses the currently loaded package info from
// WebViewFactory, so we have to fake it.
implPackageInfo = appContext.getPackageManager().getPackageInfo(
getImplPackageName(appContext), PackageManager.GET_META_DATA);
Field packageInfo = WebViewFactory.class.getDeclaredField("sPackageInfo");
packageInfo.setAccessible(true);
packageInfo.set(null, implPackageInfo);
// TODO(torne): Figure out how to load assets for production.
// Load assets using the WebViewDelegate.
Constructor constructor = WebViewDelegate.class.getDeclaredConstructor();
constructor.setAccessible(true);
delegate = (WebViewDelegate) constructor.newInstance();
} catch (Exception e) {
throw new AndroidRuntimeException(e);
}
delegate.addWebViewAssetPath(appContext);
return delegate.getPackageId(appContext.getResources(), implPackageInfo.packageName);
}
/**
* Asynchronously creates and initializes WebLayer. Calling this more than once returns the same
* object.
......@@ -97,9 +108,10 @@ public final class WebLayer {
public static ListenableFuture<WebLayer> create(Context appContext)
throws UnsupportedVersionException {
if (sFuture == null) {
IWebLayer iWebLayer = connectToWebLayerImplementation(
appContext.getApplicationContext());
sFuture = new WebLayerLoadFuture(iWebLayer, appContext);
Context remoteContext = createRemoteContext(appContext.getApplicationContext());
IWebLayer iWebLayer = connectToWebLayerImplementation(remoteContext);
int resourcesPackageId = loadAssets(appContext, remoteContext);
sFuture = new WebLayerLoadFuture(iWebLayer, remoteContext, resourcesPackageId);
}
return sFuture;
}
......@@ -110,7 +122,7 @@ public final class WebLayer {
private static final class WebLayerLoadFuture extends ListenableFuture<WebLayer> {
private final IWebLayer mIWebLayer;
WebLayerLoadFuture(IWebLayer iWebLayer, Context application) {
WebLayerLoadFuture(IWebLayer iWebLayer, Context remoteContext, int resourcesPackageId) {
mIWebLayer = iWebLayer;
ValueCallback<Boolean> loadCallback = new ValueCallback<Boolean>() {
@Override
......@@ -121,8 +133,8 @@ public final class WebLayer {
}
};
try {
iWebLayer.initAndLoadAsync(ObjectWrapper.wrap(createRemoteContext(application)),
ObjectWrapper.wrap(loadCallback));
iWebLayer.initAndLoadAsync(ObjectWrapper.wrap(remoteContext),
ObjectWrapper.wrap(loadCallback), resourcesPackageId);
} catch (RemoteException e) {
throw new APICallException(e);
}
......@@ -219,11 +231,6 @@ public final class WebLayer {
return wrapContext(getBaseContext().getApplicationContext(), remoteContext);
}
@Override
public Resources getResources() {
return remoteContext.getResources();
}
@Override
public ClassLoader getClassLoader() {
return remoteContext.getClassLoader();
......
......@@ -129,6 +129,23 @@ if (public_android_sdk) {
"//chrome/android:trichrome_library_apk",
]
}
generate_wrapper("run_weblayer_shell_webview") {
testonly = true
wrapper_script = "$root_out_dir/bin/run_weblayer_shell_webview"
executable = "//weblayer/tools/run_weblayer_shell.py"
executable_args = [
"--shell-apk-path",
"@WrappedPath(apks/WebLayerShellWebView.apk)",
"--support-apk-path",
"@WrappedPath(apks/SystemWebView.apk)",
]
deps = [
":weblayer_shell_webview_apk",
"//android_webview:system_webview_apk",
]
}
}
demo_apk_manifest = "$target_gen_dir/demo_apk_manifest/AndroidManifest.xml"
......@@ -230,6 +247,7 @@ android_apk("weblayer_support_apk") {
min_sdk_version = 21
target_sdk_version = 28
android_manifest_dep = ":weblayer_support_manifest"
shared_resources = true
native_lib_version_rule = "//build/util:chrome_version_json"
_native_lib_file =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment