1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Copyright (c) 2013 Intel Corporation. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
6 package org.xwalk.core;
8 import android.app.Activity;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.content.SharedPreferences;
12 import android.graphics.Rect;
13 import android.os.Bundle;
14 import android.text.TextUtils;
15 import android.util.AttributeSet;
16 import android.view.ViewGroup;
17 import android.webkit.WebResourceResponse;
18 import android.widget.FrameLayout;
20 import org.chromium.base.CalledByNative;
21 import org.chromium.base.JNINamespace;
22 import org.chromium.base.ThreadUtils;
23 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
24 import org.chromium.content.browser.ContentVideoView;
25 import org.chromium.content.browser.ContentView;
26 import org.chromium.content.browser.ContentViewCore;
27 import org.chromium.content.browser.ContentViewRenderView;
28 import org.chromium.content.browser.ContentViewStatics;
29 import org.chromium.content.browser.LoadUrlParams;
30 import org.chromium.content.browser.NavigationHistory;
31 import org.chromium.media.MediaPlayerBridge;
32 import org.chromium.ui.base.ActivityWindowAndroid;
34 @JNINamespace("xwalk")
36 * This class is the implementation class for XWalkView by calling internal
39 public class XWalkContent extends FrameLayout {
40 private ContentViewCore mContentViewCore;
41 private ContentView mContentView;
42 private ContentViewRenderView mContentViewRenderView;
43 private ActivityWindowAndroid mWindow;
44 private XWalkView mXWalkView;
45 private XWalkContentsClientBridge mContentsClientBridge;
46 private XWalkContentsIoThreadClient mIoThreadClient;
47 private XWalkWebContentsDelegateAdapter mXWalkContentsDelegateAdapter;
48 private XWalkSettings mSettings;
49 private XWalkGeolocationPermissions mGeolocationPermissions;
50 private XWalkLaunchScreenManager mLaunchScreenManager;
54 boolean mReadyToLoad = false;
55 String mPendingUrl = null;
57 public XWalkContent(Context context, AttributeSet attrs, XWalkView xwView) {
58 super(context, attrs);
60 // Initialize the WebContensDelegate.
62 mContentsClientBridge = new XWalkContentsClientBridge(mXWalkView);
63 mXWalkContentsDelegateAdapter = new XWalkWebContentsDelegateAdapter(
64 mContentsClientBridge);
65 mIoThreadClient = new XWalkIoThreadClientImpl();
67 // Initialize mWindow which is needed by content
68 mWindow = new ActivityWindowAndroid(xwView.getActivity());
70 // Initialize ContentViewRenderView
71 mContentViewRenderView = new ContentViewRenderView(context, mWindow) {
72 protected void onReadyToRender() {
73 if (mPendingUrl != null) {
74 doLoadUrl(mPendingUrl);
81 mLaunchScreenManager = new XWalkLaunchScreenManager(context, mXWalkView);
82 mContentViewRenderView.registerFirstRenderedFrameListener(mLaunchScreenManager);
83 addView(mContentViewRenderView,
84 new FrameLayout.LayoutParams(
85 FrameLayout.LayoutParams.MATCH_PARENT,
86 FrameLayout.LayoutParams.MATCH_PARENT));
88 mXWalkContent = nativeInit(mXWalkContentsDelegateAdapter, mContentsClientBridge);
89 mWebContents = nativeGetWebContents(mXWalkContent, mIoThreadClient,
90 mContentsClientBridge.getInterceptNavigationDelegate());
92 // Initialize ContentView.
93 mContentView = ContentView.newInstance(getContext(), mWebContents, mWindow);
95 new FrameLayout.LayoutParams(
96 FrameLayout.LayoutParams.MATCH_PARENT,
97 FrameLayout.LayoutParams.MATCH_PARENT));
98 mContentView.setContentViewClient(mContentsClientBridge);
100 mContentViewRenderView.setCurrentContentView(mContentView);
102 // For addJavascriptInterface
103 mContentViewCore = mContentView.getContentViewCore();
104 mContentsClientBridge.installWebContentsObserver(mContentViewCore);
106 mContentView.getContentViewCore().setDownloadDelegate(mContentsClientBridge);
108 // Set the third argument isAccessFromFileURLsGrantedByDefault to false, so that
109 // the members mAllowUniversalAccessFromFileURLs and mAllowFileAccessFromFileURLs
110 // won't be changed from false to true at the same time in the constructor of
111 // XWalkSettings class.
112 mSettings = new XWalkSettings(getContext(), mWebContents, false);
113 // Enable AllowFileAccessFromFileURLs, so that files under file:// path could be
114 // loaded by XMLHttpRequest.
115 mSettings.setAllowFileAccessFromFileURLs(true);
117 SharedPreferences sharedPreferences = new InMemorySharedPreferences();
118 mGeolocationPermissions = new XWalkGeolocationPermissions(sharedPreferences);
120 MediaPlayerBridge.setResourceLoadingFilter(
121 new XWalkMediaPlayerResourceLoadingFilter());
124 void doLoadUrl(String url) {
125 //TODO(Xingnan): Configure appropriate parameters here.
126 // Handle the same url loading by parameters.
127 if (TextUtils.equals(url, mContentView.getUrl())) {
128 mContentView.getContentViewCore().reload(true);
130 LoadUrlParams params = new LoadUrlParams(url);
131 params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE);
132 mContentView.loadUrl(params);
135 mContentView.requestFocus();
138 public void loadUrl(String url) {
148 public void reload() {
150 mContentView.getContentViewCore().reload(true);
154 public String getUrl() {
155 String url = mContentView.getUrl();
156 if (url == null || url.trim().isEmpty()) return null;
160 public String getTitle() {
161 String title = mContentView.getTitle().trim();
162 if (title == null) title = "";
166 public void addJavascriptInterface(Object object, String name) {
167 mContentViewCore.addJavascriptInterface(object, name);
170 public void setXWalkWebChromeClient(XWalkWebChromeClient client) {
171 mContentsClientBridge.setXWalkWebChromeClient(client);
174 public XWalkWebChromeClient getXWalkWebChromeClient() {
175 return mContentsClientBridge.getXWalkWebChromeClient();
178 public void setXWalkClient(XWalkClient client) {
179 mContentsClientBridge.setXWalkClient(client);
182 public void setDownloadListener(DownloadListener listener) {
183 mContentsClientBridge.setDownloadListener(listener);
186 public void setNavigationHandler(XWalkNavigationHandler handler) {
187 mContentsClientBridge.setNavigationHandler(handler);
190 public void setNotificationService(XWalkNotificationService service) {
191 mContentsClientBridge.setNotificationService(service);
194 public void onPause() {
195 mContentView.onHide();
198 public void onResume() {
199 mContentView.onShow();
202 public void onActivityResult(int requestCode, int resultCode, Intent data) {
203 mWindow.onActivityResult(requestCode, resultCode, data);
206 public boolean onNewIntent(Intent intent) {
207 return mContentsClientBridge.onNewIntent(intent);
210 public void clearCache(boolean includeDiskFiles) {
211 if (mXWalkContent == 0) return;
212 nativeClearCache(mXWalkContent, includeDiskFiles);
215 public void clearHistory() {
216 mContentView.getContentViewCore().clearHistory();
219 public boolean canGoBack() {
220 return mContentView.canGoBack();
223 public void goBack() {
224 mContentView.goBack();
227 public boolean canGoForward() {
228 return mContentView.canGoForward();
231 public void goForward() {
232 mContentView.goForward();
235 public void stopLoading() {
236 mContentView.getContentViewCore().stopLoading();
239 // TODO(Guangzhen): ContentViewStatics will be removed in upstream,
240 // details in content_view_statics.cc.
241 // We need follow up after upstream updates that.
242 public void pauseTimers() {
243 ContentViewStatics.setWebKitSharedTimersSuspended(true);
246 public void resumeTimers() {
247 ContentViewStatics.setWebKitSharedTimersSuspended(false);
250 public String getOriginalUrl() {
251 NavigationHistory history = mContentViewCore.getNavigationHistory();
252 int currentIndex = history.getCurrentEntryIndex();
253 if (currentIndex >= 0 && currentIndex < history.getEntryCount()) {
254 return history.getEntryAtIndex(currentIndex).getOriginalUrl();
259 public String getVersion() {
260 if (mXWalkContent == 0) return "";
261 return nativeGetVersion(mXWalkContent);
264 public void setNetworkAvailable(boolean networkUp) {
265 if (mXWalkContent == 0) return;
266 nativeSetJsOnlineProperty(mXWalkContent, networkUp);
269 // For instrumentation test.
270 public ContentViewCore getContentViewCoreForTest() {
271 return mContentViewCore;
274 // For instrumentation test.
275 public void installWebContentsObserverForTest(XWalkContentsClient contentClient) {
276 contentClient.installWebContentsObserver(mContentViewCore);
279 public String devToolsAgentId() {
280 if (mXWalkContent == 0) return "";
281 return nativeDevToolsAgentId(mXWalkContent);
284 public XWalkSettings getSettings() {
288 public void loadAppFromManifest(String path, String manifest) {
289 if (path == null || manifest == null || mXWalkContent == 0) {
293 if (!nativeSetManifest(mXWalkContent, path, manifest)) {
294 throw new RuntimeException("Failed to parse the manifest file.");
298 public WebBackForwardList copyBackForwardList() {
299 return new WebBackForwardList(mContentViewCore.getNavigationHistory());
302 public static final String SAVE_RESTORE_STATE_KEY = "XWALKVIEW_STATE";
304 public WebBackForwardList saveState(Bundle outState) {
305 if (outState == null) return null;
307 byte[] state = nativeGetState(mXWalkContent);
308 if (state == null) return null;
310 outState.putByteArray(SAVE_RESTORE_STATE_KEY, state);
311 return copyBackForwardList();
314 public WebBackForwardList restoreState(Bundle inState) {
315 if (inState == null) return null;
317 byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY);
318 if (state == null) return null;
320 boolean result = nativeSetState(mXWalkContent, state);
322 // The onUpdateTitle callback normally happens when a page is loaded,
323 // but is optimized out in the restoreState case because the title is
324 // already restored. See WebContentsImpl::UpdateTitleForEntry. So we
325 // call the callback explicitly here.
327 mContentsClientBridge.onUpdateTitle(mContentViewCore.getTitle());
330 return result ? copyBackForwardList() : null;
333 public boolean isFullscreen() {
334 return mWebContents != 0 && getXWalkWebChromeClient() != null &&
335 getXWalkWebChromeClient().isFullscreen();
338 public void exitFullscreen() {
339 if (isFullscreen()) {
340 mContentsClientBridge.exitFullscreen(mWebContents);
345 public void onGetUrlFromManifest(String url) {
346 if (url != null && !url.isEmpty()) {
352 public void onGetUrlAndLaunchScreenFromManifest(String url, String readyWhen) {
353 if (url == null || url.isEmpty()) return;
354 mLaunchScreenManager.displayLaunchScreen(readyWhen);
355 mContentsClientBridge.registerPageLoadListener(mLaunchScreenManager);
359 public void destroy() {
360 if (mXWalkContent == 0) return;
362 // Reset existing notification service in order to destruct it.
363 setNotificationService(null);
364 // Remove its children used for page rendering from view hierarchy.
365 removeView(mContentView);
366 removeView(mContentViewRenderView);
367 mContentViewRenderView.setCurrentContentView(null);
369 // Destroy the native resources.
370 mContentViewRenderView.destroy();
371 mContentView.destroy();
373 nativeDestroy(mXWalkContent);
377 public int getRoutingID() {
378 return nativeGetRoutingID(mXWalkContent);
381 //--------------------------------------------------------------------------------------------
382 private class XWalkIoThreadClientImpl implements XWalkContentsIoThreadClient {
383 // All methods are called on the IO thread.
386 public int getCacheMode() {
387 return mSettings.getCacheMode();
391 public InterceptedRequestData shouldInterceptRequest(final String url,
392 boolean isMainFrame) {
394 WebResourceResponse webResourceResponse = mContentsClientBridge.shouldInterceptRequest(url);
395 InterceptedRequestData interceptedRequestData = null;
397 if (webResourceResponse == null) {
398 mContentsClientBridge.getCallbackHelper().postOnLoadResource(url);
400 if (isMainFrame && webResourceResponse.getData() == null) {
401 mContentsClientBridge.getCallbackHelper().postOnReceivedError(-1, null, url);
403 interceptedRequestData = new InterceptedRequestData(webResourceResponse.getMimeType(),
404 webResourceResponse.getEncoding(),
405 webResourceResponse.getData());
407 return interceptedRequestData;
411 public boolean shouldBlockContentUrls() {
412 return !mSettings.getAllowContentAccess();
416 public boolean shouldBlockFileUrls() {
417 return !mSettings.getAllowFileAccess();
421 public boolean shouldBlockNetworkLoads() {
422 return mSettings.getBlockNetworkLoads();
426 public void onDownloadStart(String url,
428 String contentDisposition,
430 long contentLength) {
431 mContentsClientBridge.getCallbackHelper().postOnDownloadStart(url, userAgent,
432 contentDisposition, mimeType, contentLength);
436 public void newLoginRequest(String realm, String account, String args) {
437 mContentsClientBridge.getCallbackHelper().postOnReceivedLoginRequest(realm, account, args);
441 private class XWalkGeolocationCallback implements XWalkGeolocationPermissions.Callback {
443 public void invoke(final String origin, final boolean allow, final boolean retain) {
444 ThreadUtils.runOnUiThread(new Runnable() {
449 mGeolocationPermissions.allow(origin);
451 mGeolocationPermissions.deny(origin);
454 nativeInvokeGeolocationCallback(mXWalkContent, allow, origin);
461 private void onGeolocationPermissionsShowPrompt(String origin) {
462 // Reject if geolocation is disabled, or the origin has a retained deny.
463 if (!mSettings.getGeolocationEnabled()) {
464 nativeInvokeGeolocationCallback(mXWalkContent, false, origin);
467 // Allow if the origin has a retained allow.
468 if (mGeolocationPermissions.hasOrigin(origin)) {
469 nativeInvokeGeolocationCallback(mXWalkContent,
470 mGeolocationPermissions.isOriginAllowed(origin),
474 mContentsClientBridge.onGeolocationPermissionsShowPrompt(
475 origin, new XWalkGeolocationCallback());
479 public void onGeolocationPermissionsHidePrompt() {
480 mContentsClientBridge.onGeolocationPermissionsHidePrompt();
483 private native int nativeInit(XWalkWebContentsDelegate webViewContentsDelegate,
484 XWalkContentsClientBridge bridge);
485 private static native void nativeDestroy(int nativeXWalkContent);
486 private native int nativeGetWebContents(int nativeXWalkContent,
487 XWalkContentsIoThreadClient ioThreadClient,
488 InterceptNavigationDelegate delegate);
489 private native void nativeClearCache(int nativeXWalkContent, boolean includeDiskFiles);
490 private native String nativeDevToolsAgentId(int nativeXWalkContent);
491 private native String nativeGetVersion(int nativeXWalkContent);
492 private native void nativeSetJsOnlineProperty(int nativeXWalkContent, boolean networkUp);
493 private native boolean nativeSetManifest(int nativeXWalkContent, String path, String manifest);
494 private native int nativeGetRoutingID(int nativeXWalkContent);
495 private native void nativeInvokeGeolocationCallback(
496 int nativeXWalkContent, boolean value, String requestingFrame);
497 private native byte[] nativeGetState(int nativeXWalkContent);
498 private native boolean nativeSetState(int nativeXWalkContent, byte[] state);