Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / android / core / src / org / xwalk / core / XWalkContent.java
index 18cb146..ea3f43f 100644 (file)
@@ -1,5 +1,5 @@
 // Copyright 2013 The Chromium Authors. All rights reserved.
-// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Copyright (c) 2013-2014 Intel Corporation. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -13,15 +13,19 @@ import android.graphics.Rect;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.ViewGroup;
+import android.webkit.ValueCallback;
 import android.webkit.WebResourceResponse;
 import android.widget.FrameLayout;
 
+import java.io.IOException;
+import java.io.InputStream;
+
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
 import org.chromium.base.ThreadUtils;
 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
-import org.chromium.content.browser.ContentVideoView;
 import org.chromium.content.browser.ContentView;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content.browser.ContentViewRenderView;
@@ -36,11 +40,13 @@ import org.chromium.ui.base.ActivityWindowAndroid;
  * This class is the implementation class for XWalkView by calling internal
  * various classes.
  */
-public class XWalkContent extends FrameLayout {
+class XWalkContent extends FrameLayout implements XWalkPreferences.KeyValueChangeListener {
+    private static String TAG = "XWalkContent";
     private ContentViewCore mContentViewCore;
     private ContentView mContentView;
     private ContentViewRenderView mContentViewRenderView;
     private ActivityWindowAndroid mWindow;
+    private XWalkDevToolsServer mDevToolsServer;
     private XWalkView mXWalkView;
     private XWalkContentsClientBridge mContentsClientBridge;
     private XWalkContentsIoThreadClient mIoThreadClient;
@@ -49,10 +55,11 @@ public class XWalkContent extends FrameLayout {
     private XWalkGeolocationPermissions mGeolocationPermissions;
     private XWalkLaunchScreenManager mLaunchScreenManager;
 
-    int mXWalkContent;
-    int mWebContents;
+    long mXWalkContent;
+    long mWebContents;
     boolean mReadyToLoad = false;
     String mPendingUrl = null;
+    String mPendingData = null;
 
     public XWalkContent(Context context, AttributeSet attrs, XWalkView xwView) {
         super(context, attrs);
@@ -71,8 +78,9 @@ public class XWalkContent extends FrameLayout {
         mContentViewRenderView = new ContentViewRenderView(context, mWindow) {
             protected void onReadyToRender() {
                 if (mPendingUrl != null) {
-                    doLoadUrl(mPendingUrl);
+                    doLoadUrl(mPendingUrl, mPendingData);
                     mPendingUrl = null;
+                    mPendingData = null;
                 }
 
                 mReadyToLoad = true;
@@ -119,15 +127,23 @@ public class XWalkContent extends FrameLayout {
 
         MediaPlayerBridge.setResourceLoadingFilter(
                 new XWalkMediaPlayerResourceLoadingFilter());
+
+        XWalkPreferences.load(this);
     }
 
-    void doLoadUrl(String url) {
-        //TODO(Xingnan): Configure appropriate parameters here.
+    void doLoadUrl(String url, String content) {
         // Handle the same url loading by parameters.
-        if (TextUtils.equals(url, mContentView.getUrl())) {
+        if (url != null && !url.isEmpty() &&
+                TextUtils.equals(url, mContentView.getUrl())) {
             mContentView.getContentViewCore().reload(true);
         } else {
-            LoadUrlParams params = new LoadUrlParams(url);
+            LoadUrlParams params = null;
+            if (content == null || content.isEmpty()) {
+                params = new LoadUrlParams(url);
+            } else {
+                params = LoadUrlParams.createLoadDataParamsWithBaseUrl(
+                        content, "text/html", false, url, null);
+            }
             params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE);
             mContentView.loadUrl(params);
         }
@@ -135,19 +151,31 @@ public class XWalkContent extends FrameLayout {
         mContentView.requestFocus();
     }
 
-    public void loadUrl(String url) {
-        if (url == null)
+    public void loadUrl(String url, String data) {
+        if ((url == null || url.isEmpty()) &&
+                (data == null || data.isEmpty())) {
             return;
+        }
 
-        if (mReadyToLoad)
-            doLoadUrl(url);
-        else
+        if (mReadyToLoad) {
+            doLoadUrl(url, data);
+        } else {
             mPendingUrl = url;
+            mPendingData = data;
+        }
     }
 
-    public void reload() {
+    public void reload(int mode) {
         if (mReadyToLoad) {
-            mContentView.getContentViewCore().reload(true);
+            switch (mode) {
+                case XWalkView.RELOAD_IGNORE_CACHE:
+                    mContentView.getContentViewCore().reloadIgnoringCache(true);
+                    break;
+                case XWalkView.RELOAD_NORMAL:
+                default:
+                    mContentView.getContentViewCore().reload(true);
+
+            }
         }
     }
 
@@ -164,7 +192,27 @@ public class XWalkContent extends FrameLayout {
     }
 
     public void addJavascriptInterface(Object object, String name) {
-        mContentViewCore.addJavascriptInterface(object, name);
+        mContentViewCore.addPossiblyUnsafeJavascriptInterface(object, name,
+                JavascriptInterface.class);
+    }
+
+    public void evaluateJavascript(String script, ValueCallback<String> callback) {
+        final ValueCallback<String>  fCallback = callback;
+        ContentViewCore.JavaScriptCallback coreCallback = new ContentViewCore.JavaScriptCallback() {
+            @Override
+            public void handleJavaScriptResult(String jsonResult) {
+                fCallback.onReceiveValue(jsonResult);
+            }
+        };
+        mContentViewCore.evaluateJavaScript(script, coreCallback);
+    }
+
+    public void setUIClient(XWalkUIClient client) {
+        mContentsClientBridge.setUIClient(client);
+    }
+
+    public void setResourceClient(XWalkResourceClient client) {
+        mContentsClientBridge.setResourceClient(client);
     }
 
     public void setXWalkWebChromeClient(XWalkWebChromeClient client) {
@@ -232,6 +280,10 @@ public class XWalkContent extends FrameLayout {
         mContentView.goForward();
     }
 
+    void navigateTo(int offset)  {
+        mContentView.getContentViewCore().goToOffset(offset);
+    }
+
     public void stopLoading() {
         mContentView.getContentViewCore().stopLoading();
     }
@@ -256,7 +308,7 @@ public class XWalkContent extends FrameLayout {
         return null;
     }
 
-    public String getVersion() {
+    public String getXWalkVersion() {
         if (mXWalkContent == 0) return "";
         return nativeGetVersion(mXWalkContent);
     }
@@ -285,33 +337,56 @@ public class XWalkContent extends FrameLayout {
         return mSettings;
     }
 
-    public void loadAppFromManifest(String path, String manifest) {
-        if (path == null || manifest == null || mXWalkContent == 0) {
+    public void loadAppFromManifest(String url, String data) {
+        if (mXWalkContent == 0 ||
+                ((url == null || url.isEmpty()) &&
+                        (data == null || data.isEmpty()))) {
             return;
         }
 
-        if (!nativeSetManifest(mXWalkContent, path, manifest)) {
-            throw new RuntimeException("Failed to parse the manifest file.");
+        String content = data;
+        // If the data of manifest.json is not set, try to load it.
+        if (data == null || data.isEmpty()) {
+            try {
+                content = AndroidProtocolHandler.getUrlContent(mXWalkView.getActivity(), url);
+            } catch (IOException e) {
+                throw new RuntimeException("Failed to read the manifest: " + url);
+            }
+        }
+
+        // Calculate the base url of manifestUrl. Used by native side.
+        // TODO(yongsheng): It's from runtime side. Need to find a better way
+        // to get base url.
+        String baseUrl = url;
+        int position = url.lastIndexOf("/");
+        if (position != -1) {
+            baseUrl = url.substring(0, position + 1);
+        } else {
+            Log.w(TAG, "The url of manifest.json is probably not set correctly.");
+        }
+
+        if (!nativeSetManifest(mXWalkContent, baseUrl, content)) {
+            throw new RuntimeException("Failed to parse the manifest file: " + url);
         }
     }
 
-    public WebBackForwardList copyBackForwardList() {
-        return new WebBackForwardList(mContentViewCore.getNavigationHistory());
+    public XWalkNavigationHistory getNavigationHistory() {
+        return new XWalkNavigationHistory(mXWalkView, mContentViewCore.getNavigationHistory());
     }
 
     public static final String SAVE_RESTORE_STATE_KEY = "XWALKVIEW_STATE";
 
-    public WebBackForwardList saveState(Bundle outState) {
+    public XWalkNavigationHistory saveState(Bundle outState) {
         if (outState == null) return null;
 
         byte[] state = nativeGetState(mXWalkContent);
         if (state == null) return null;
 
         outState.putByteArray(SAVE_RESTORE_STATE_KEY, state);
-        return copyBackForwardList();
+        return getNavigationHistory();
     }
 
-    public WebBackForwardList restoreState(Bundle inState) {
+    public XWalkNavigationHistory restoreState(Bundle inState) {
         if (inState == null) return null;
 
         byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY);
@@ -327,16 +402,15 @@ public class XWalkContent extends FrameLayout {
             mContentsClientBridge.onUpdateTitle(mContentViewCore.getTitle());
         }
 
-        return result ? copyBackForwardList() : null;
+        return result ? getNavigationHistory() : null;
     }
 
-    public boolean isFullscreen() {
-        return mWebContents != 0 && getXWalkWebChromeClient() != null &&
-                getXWalkWebChromeClient().isFullscreen();
+    boolean hasEnteredFullscreen() {
+        return mContentsClientBridge.hasEnteredFullscreen();
     }
 
-    public void exitFullscreen() {
-        if (isFullscreen()) {
+    void exitFullscreen() {
+        if (hasEnteredFullscreen()) {
             mContentsClientBridge.exitFullscreen(mWebContents);
         }
     }
@@ -344,26 +418,27 @@ public class XWalkContent extends FrameLayout {
     @CalledByNative
     public void onGetUrlFromManifest(String url) {
         if (url != null && !url.isEmpty()) {
-            loadUrl(url);
+            loadUrl(url, null);
         }
     }
 
     @CalledByNative
-    public void onGetUrlAndLaunchScreenFromManifest(String url, String readyWhen) {
+    public void onGetUrlAndLaunchScreenFromManifest(String url, String readyWhen, String imageBorder) {
         if (url == null || url.isEmpty()) return;
-        mLaunchScreenManager.displayLaunchScreen(readyWhen);
+        mLaunchScreenManager.displayLaunchScreen(readyWhen, imageBorder);
         mContentsClientBridge.registerPageLoadListener(mLaunchScreenManager);
-        loadUrl(url);
+        loadUrl(url, null);
     }
 
     @CalledByNative
     public void onGetFullscreenFlagFromManifest(boolean enterFullscreen) {
-        if (enterFullscreen) getXWalkWebChromeClient().onToggleFullscreen(true);
+        if (enterFullscreen) mContentsClientBridge.onToggleFullscreen(true);
     }
 
     public void destroy() {
         if (mXWalkContent == 0) return;
 
+        XWalkPreferences.unload(this);
         // Reset existing notification service in order to destruct it.
         setNotificationService(null);
         // Remove its children used for page rendering from view hierarchy.
@@ -396,6 +471,10 @@ public class XWalkContent extends FrameLayout {
         public InterceptedRequestData shouldInterceptRequest(final String url,
                 boolean isMainFrame) {
 
+            // Notify a resource load is started. This is not the best place to start the callback
+            // but it's a workable way.
+            mContentsClientBridge.getCallbackHelper().postOnResourceLoadStarted(url);
+
             WebResourceResponse webResourceResponse = mContentsClientBridge.shouldInterceptRequest(url);
             InterceptedRequestData interceptedRequestData = null;
 
@@ -403,7 +482,8 @@ public class XWalkContent extends FrameLayout {
                 mContentsClientBridge.getCallbackHelper().postOnLoadResource(url);
             } else {
                 if (isMainFrame && webResourceResponse.getData() == null) {
-                    mContentsClientBridge.getCallbackHelper().postOnReceivedError(-1, null, url);
+                    mContentsClientBridge.getCallbackHelper().postOnReceivedError(
+                            XWalkResourceClient.ERROR_UNKNOWN, null, url);
                 }
                 interceptedRequestData = new InterceptedRequestData(webResourceResponse.getMimeType(),
                                                                     webResourceResponse.getEncoding(),
@@ -485,20 +565,63 @@ public class XWalkContent extends FrameLayout {
         mContentsClientBridge.onGeolocationPermissionsHidePrompt();
     }
 
-    private native int nativeInit(XWalkWebContentsDelegate webViewContentsDelegate,
+    public String enableRemoteDebugging(int allowedUid) {
+        // Chrome looks for "devtools_remote" pattern in the name of a unix domain socket
+        // to identify a debugging page
+        final String socketName = getContext().getApplicationContext().getPackageName() + "_devtools_remote";
+        if (mDevToolsServer == null) {
+            mDevToolsServer = new XWalkDevToolsServer(socketName);
+            mDevToolsServer.allowConnectionFromUid(allowedUid);
+            mDevToolsServer.setRemoteDebuggingEnabled(true);
+        }
+        // devtools/page is hardcoded in devtools_http_handler_impl.cc (kPageUrlPrefix)
+        return "ws://" + socketName + "/devtools/page/" + devToolsAgentId();
+    }
+
+    // Enables remote debugging and returns the URL at which the dev tools server is listening
+    // for commands. Only the current process is allowed to connect to the server.
+    String enableRemoteDebugging() {
+        return enableRemoteDebugging(getContext().getApplicationInfo().uid);
+    }
+
+    void disableRemoteDebugging() {
+        if (mDevToolsServer ==  null) return;
+
+        if (mDevToolsServer.isRemoteDebuggingEnabled()) {
+            mDevToolsServer.setRemoteDebuggingEnabled(false);
+        }
+        mDevToolsServer.destroy();
+        mDevToolsServer = null;
+    }
+
+    @Override
+    public void onKeyValueChanged(String key, boolean value) {
+        if (key == XWalkPreferences.REMOTE_DEBUGGING) {
+            if (value) enableRemoteDebugging();
+            else disableRemoteDebugging();
+        }
+    }
+
+    public void setOverlayVideoMode(boolean enabled) {
+        if (mContentViewRenderView != null) {
+            mContentViewRenderView.setOverlayVideoMode(enabled);
+        }
+    }
+
+    private native long nativeInit(XWalkWebContentsDelegate webViewContentsDelegate,
             XWalkContentsClientBridge bridge);
-    private static native void nativeDestroy(int nativeXWalkContent);
-    private native int nativeGetWebContents(int nativeXWalkContent,
+    private static native void nativeDestroy(long nativeXWalkContent);
+    private native long nativeGetWebContents(long nativeXWalkContent,
             XWalkContentsIoThreadClient ioThreadClient,
             InterceptNavigationDelegate delegate);
-    private native void nativeClearCache(int nativeXWalkContent, boolean includeDiskFiles);
-    private native String nativeDevToolsAgentId(int nativeXWalkContent);
-    private native String nativeGetVersion(int nativeXWalkContent);
-    private native void nativeSetJsOnlineProperty(int nativeXWalkContent, boolean networkUp);
-    private native boolean nativeSetManifest(int nativeXWalkContent, String path, String manifest);
-    private native int nativeGetRoutingID(int nativeXWalkContent);
+    private native void nativeClearCache(long nativeXWalkContent, boolean includeDiskFiles);
+    private native String nativeDevToolsAgentId(long nativeXWalkContent);
+    private native String nativeGetVersion(long nativeXWalkContent);
+    private native void nativeSetJsOnlineProperty(long nativeXWalkContent, boolean networkUp);
+    private native boolean nativeSetManifest(long nativeXWalkContent, String path, String manifest);
+    private native int nativeGetRoutingID(long nativeXWalkContent);
     private native void nativeInvokeGeolocationCallback(
-            int nativeXWalkContent, boolean value, String requestingFrame);
-    private native byte[] nativeGetState(int nativeXWalkContent);
-    private native boolean nativeSetState(int nativeXWalkContent, byte[] state);
+            long nativeXWalkContent, boolean value, String requestingFrame);
+    private native byte[] nativeGetState(long nativeXWalkContent);
+    private native boolean nativeSetState(long nativeXWalkContent, byte[] state);
 }