├── .gitignore ├── README.md ├── config └── buildvms.sh.template ├── res ├── raw │ └── blank_html.html └── values │ └── strings.xml ├── script ├── README.md ├── download.sh ├── pull.sh └── push.sh ├── src └── us │ └── costan │ └── chrome │ ├── ChromeCookieManager.java │ ├── ChromeHttpAuthHandler.java │ ├── ChromeJavascriptInterface.java │ ├── ChromeJsPromptResult.java │ ├── ChromeJsResult.java │ ├── ChromeSettings.java │ ├── ChromeSslErrorHandler.java │ ├── ChromeView.java │ ├── ChromeViewClient.java │ ├── ChromeWebClient.java │ └── impl │ ├── ChromeAwContentsClientProxy.java │ ├── ChromeHttpAuthHandlerProxy.java │ ├── ChromeInitializer.java │ ├── ChromeJsPromptResultProxy.java │ ├── ChromeJsResultReceiverProxy.java │ ├── ChromeSettingsProxy.java │ └── ChromeSslErrorHandlerProxy.java └── vm ├── README.md ├── build.sh └── setup.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Files for the dex VM. 2 | *.dex 3 | 4 | # Java class files. 5 | *.class 6 | 7 | # Generated files. 8 | bin/ 9 | gen/ 10 | 11 | # Local configuration file (sdk path, etc). 12 | local.properties 13 | 14 | # Vim. 15 | *.sw* 16 | 17 | # Downloaded build. 18 | build 19 | 20 | # Build VM configuration. 21 | config/buildvms.sh 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecation Notice 2 | 3 | This project is un-maintained. The recommended alternative is 4 | [the Crosswalk Project](https://crosswalk-project.org/). 5 | 6 | I did not have the time to keep the project up to date. In the mean 7 | time, the fine folks at Intel did a great job of embedding Chromium 8 | using the Content Shell API, which is what Chromium's developers 9 | intended. Therefore, I cannot justify spending any time on this. 10 | The original README and the code are here for historical purposes. 11 | 12 | I think that [the Crosswalk Project](https://crosswalk-project.org/) 13 | will meet all your embedding needs, and I'm contributing to it. 14 | 15 | # ChromeView Source Code 16 | 17 | ChormeView works like Android's WebView, but is backed by the latest Chromium 18 | code. 19 | 20 | [pwnall/chromeview](https://github.com/pwnall/chromeview) contains a binary 21 | distribution of ChromeView, with all the hard-to-build Chrome bits. This 22 | repository gets rebased, because it would become too large otherwise. 23 | 24 | [pwnall/chromeview-src](https://github.com/pwnall/chromeview-src) has the 25 | original source code (that is not pulled in from the Chromium project) and the 26 | scripts for building and extracting the bits from the Chromium source tree. 27 | 28 | 29 | ## Why ChromeView 30 | 31 | ChromeView lets you ship your own Chromium code, instead of using whatever 32 | version comes with your user's Android image. This gives your application 33 | early access to the newest features in Chromium, and removes the variability 34 | due to different WebView implementations in different versions of Android. 35 | 36 | 37 | ## Setting Up 38 | 39 | This section explains how to set up your Android project to use ChromeView. 40 | 41 | ### Get the Code 42 | 43 | Check out the repository in your Eclipse workspace, and make your project use 44 | ChromeView as a library. In Eclipse, right-click your project directory, select 45 | `Properties`, choose the `Android` category, and click on the `Add` button in 46 | the `Library section`. 47 | 48 | ### Copy Data 49 | 50 | Copy `assets/webviewchromium.pak` to your project's `assets` directory. 51 | 52 | In your `Application` subclass, call `ChromeView.initialize` and pass it the 53 | application's context. For example, 54 | 55 | ### Initialize Chromium 56 | 57 | ```java 58 | import us.costan.chrome.ChromeView; 59 | import android.app.Application; 60 | 61 | public class MyApplication extends Application { 62 | @Override 63 | public void onCreate() { 64 | super.onCreate(); 65 | ChromeView.initialize(this); 66 | } 67 | } 68 | ``` 69 | 70 | Now you can use ChromeView in the same contexts as you would use WebView. 71 | 72 | ### Make Some Noise 73 | 74 | If you use this project and want to help move it along, please star the 75 | following bugs. 76 | 77 | * [crbug.com/113088](http://crbug.com/113088) 78 | * [crbug.com/234907](http://crbug.com/234907) and 79 | * [this Android bug](https://code.google.com/p/android/issues/detail?id=35748) 80 | 81 | 82 | ## Usage 83 | 84 | To access ChromeView in the graphical layout editor, go to the `Palette`, 85 | expand the `Custom and Library Views` section, and click the `Refresh` button. 86 | 87 | ChromeView supports most of the WebView methods. For example, 88 | 89 | ```java 90 | ChromeView chromeView = (ChromeView)findViewById(R.id.gameUiView); 91 | chromeView.getSettings().setJavaScriptEnabled(true); 92 | chromeView.loadUrl("http://www.google.com"); 93 | ``` 94 | 95 | ### JavaScript 96 | 97 | ChromeView's `addJavaScriptInterface` exposes public methods that are annotated 98 | with `@ChromeJavascriptInterface`. This is because WebView's 99 | `@JavascriptInterface` is only available on Android 4.2 and above, but 100 | ChromeView targets 4.0 and 4.1 as well. 101 | 102 | ```java 103 | import us.costan.chrome.ChromeJavascriptInterface; 104 | 105 | public class JsBindings { 106 | @ChromeJavascriptInterface 107 | public String getHello() { 108 | return "Hello world"; 109 | } 110 | } 111 | 112 | chromeView.addJavascriptInterface(new JsBindings(), "AndroidBindings"); 113 | ``` 114 | 115 | ### Cookies 116 | 117 | ChromeCookieManager is ChromeView's equivalent of CookieManager. 118 | 119 | ```java 120 | ChromeCookieManager.getInstance().getCookie("https://www.google.com"); 121 | ``` 122 | 123 | ### Faster Development 124 | 125 | To speed up the application launch on real devices, remove the `libs/x86` 126 | directory. When developing on Atom devices, remove the ARM directory instead. 127 | 128 | Remember to `git checkout -- .` and get the library back before building a 129 | release APK. 130 | 131 | ### Internet Access 132 | 133 | If your application manifest doesn't specify the 134 | [INTERNET permission](http://developer.android.com/reference/android/Manifest.permission.html#INTERNET), 135 | the Chromium code behind ChromeView silentely blocks all network requests. This 136 | is mentioned here because it can be hard to debug. 137 | 138 | 139 | ## Building 140 | 141 | The bulk of this project is Chromium source code and build products. With the 142 | appropriate infrastructure, the Chromium bits can be easily updated. 143 | 144 | [crbuild/vm-build.md](crbuild/vm-build.md) contains step-by-step instructions 145 | for setting up a VM and building the Chromium for Android components used by 146 | ChromeView. 147 | 148 | Once Chromium has been successfully built, running 149 | [crbuild/update.sh](crbuild/update.sh) will copy the relevant bits from the 150 | build VM into the ChromeView source tree. 151 | 152 | 153 | ## Issues 154 | 155 | Attempting to scroll the view (by swiping a finger across the screen) does not 156 | update the displayed image. However, internally, the view is scrolled. This can 157 | be seen by displaying a stack of buttons and trying to click on the topmost 158 | one. This issue makes ChromeView mostly unusable in production. 159 | 160 | The core issue is that the integration is done via `AwContent` in the 161 | `android_webview` directory of the Chromium source tree, which is experimental 162 | and not intended for embedding use. The "right" way of doing this is to embed 163 | a `ContentView` from the `content` directory, or a `Shell` in `content/shell`. 164 | Unfortunately, these components' APIs don't match WebView nearly as well as 165 | AwContent, and they're much harder to integrate. Pull requests or a fork would 166 | be welcome. 167 | 168 | This repository is rebased often, because the large files in `lib/` would 169 | result in a huge repository if new commits were created for each build. The 170 | large files are Chromium build products. 171 | 172 | 173 | ## Contributing 174 | 175 | Please don't hesitate to send your Pull Requests! 176 | 177 | Please don't send pull requests including the binary assets or code extracted 178 | from Android (`assets/`, `libs/`, `src/com/googlecode/` and `src/org/android`). 179 | If your Pull Request requires updated Android bits, mention that in the PR 180 | description, and I will rebuild the Android bits. 181 | 182 | 183 | ## Copyright and License 184 | 185 | The directories below contain code from the 186 | [The Chromium Project](http://www.chromium.org/), which is subject to the 187 | copyright and license on the project site. 188 | 189 | * `assets/` 190 | * `libs/` 191 | * `src/com/googlecode` 192 | * `src/org/chromium` 193 | 194 | Some of the source code in `src/us/costan/chrome` has been derived from the 195 | Android source code, and is therefore covered by the 196 | [Android project licenses](http://source.android.com/source/licenses.html). 197 | 198 | The rest of the code is Copyright 2013, Victor Costan, and available under the 199 | MIT license. 200 | -------------------------------------------------------------------------------- /config/buildvms.sh.template: -------------------------------------------------------------------------------- 1 | # The URL of the VM that does ARM builds. 2 | ARM_BUILDVM=http://arm.buildbot.org 3 | 4 | # The URL of the VM that does X86 builds. 5 | # 6 | # This can be the same as the URL above, if the same VM is used for both 7 | # architectures. 8 | X86_BUILDVM=http://x86.buildbot.org 9 | -------------------------------------------------------------------------------- /res/raw/blank_html.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This page intentionally left blank. 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | text/plain 5 | -------------------------------------------------------------------------------- /script/README.md: -------------------------------------------------------------------------------- 1 | This directory contains scripts that are intended to be run on the machine used 2 | to develop ChromeView. 3 | -------------------------------------------------------------------------------- /script/download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Download the latest build from build bots. 3 | 4 | set -o errexit # Stop the script on the first error. 5 | set -o nounset # Catch un-initialized variables. 6 | 7 | # Load the configuration. 8 | if [ ! -f config/buildvms.sh ] ; then 9 | cp config/buildvms.sh.template config/buildvms.sh 10 | echo "Edit config/buildvms.sh and run this script again." 11 | exit 1 12 | fi 13 | . config/buildvms.sh 14 | 15 | # Get the latest revision from the ARM bot. 16 | REV=$(curl -fLsS $ARM_BUILDVM/LATEST_REV) 17 | 18 | # Download the arm and x86 packages. 19 | rm -rf build 20 | mkdir -p build 21 | echo -n "Downloading ARM build... " 22 | curl -fLsS $ARM_BUILDVM/archives/$REV-arm.tar.gz -o build/arm-build.tar.gz 23 | echo "done" 24 | echo -n "Downloading X86 build... " 25 | curl -fLsS $X86_BUILDVM/archives/$REV-x86.tar.gz -o build/x86-build.tar.gz 26 | echo "done" 27 | 28 | # Unpack the packages. 29 | echo Unpacking build. 30 | cd build 31 | tar -xzf x86-build.tar.gz 32 | tar -xzf arm-build.tar.gz 33 | cd .. 34 | 35 | # Remove the archives. 36 | rm build/arm-build.tar.gz 37 | rm build/x86-build.tar.gz 38 | -------------------------------------------------------------------------------- /script/pull.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copies the glue code from the chromeview sibling directory. 3 | 4 | set -o errexit # Stop the script on the first error. 5 | set -o nounset # Catch un-initialized variables. 6 | 7 | rm -rf src/ 8 | mkdir -p src/ 9 | cp -r ../chromeview/src/us src/ 10 | 11 | rm -rf res/ 12 | mkdir -p res 13 | cp -r ../chromeview/res/raw res/ 14 | mkdir -p res/values 15 | cp -r ../chromeview/res/values/strings.xml res/values/ 16 | -------------------------------------------------------------------------------- /script/push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Push the local source and downloaded build to chromeview. 3 | 4 | set -o errexit # Stop the script on the first error. 5 | set -o nounset # Catch un-initialized variables. 6 | 7 | rm -rf ../chromeview/assets 8 | cp -r build/assets ../chromeview/ 9 | 10 | rm -rf ../chromeview/libs 11 | cp -r build/libs ../chromeview/libs 12 | 13 | rm -rf ../chromeview/res 14 | cp -r build/res ../chromeview/res 15 | cp -r res/* ../chromeview/res/ 16 | 17 | rm -rf ../chromeview/src 18 | cp -r build/src ../chromeview/src 19 | cp -r src/* ../chromeview/src/ 20 | -------------------------------------------------------------------------------- /src/us/costan/chrome/ChromeCookieManager.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome; 2 | 3 | import org.chromium.android_webview.AwCookieManager; 4 | 5 | /** 6 | * ChromeView equivalent of WebView's CookieManager. 7 | * 8 | * @see android.webkit.CookieManager 9 | */ 10 | public class ChromeCookieManager { 11 | /** The class that's doing all the work. */ 12 | private AwCookieManager awCookieManager_; 13 | 14 | private ChromeCookieManager() { 15 | awCookieManager_ = new AwCookieManager(); 16 | } 17 | 18 | /** 19 | * Sets whether ChromeView instances should send and accept cookies. 20 | * @param accept whether ChromeView instances should send and accept cookies 21 | */ 22 | public void setAcceptCookie(boolean accept) { 23 | awCookieManager_.setAcceptCookie(accept); 24 | } 25 | 26 | /** 27 | * Whether the application's ChromeView instances send and accept cookies. 28 | * @return true if ChromeView instances send and accept cookies for file 29 | * scheme URLs 30 | */ 31 | public boolean acceptCookie() { 32 | return awCookieManager_.acceptCookie(); 33 | } 34 | 35 | /** 36 | * Sets a cookie for the given URL. Any existing cookie with the same host, 37 | * path and name will be replaced with the new cookie. The cookie being set 38 | * must not have expired and must not be a session cookie, otherwise it will 39 | * be ignored. 40 | * 41 | * @param url the URL for which cookie is set 42 | * @param value the cookie as a string, using the format of the 'Set-Cookie' 43 | * HTTP header 44 | */ 45 | public void setCookie(final String url, final String value) { 46 | awCookieManager_.setCookie(url, value); 47 | } 48 | 49 | /** 50 | * Gets the cookies for the given URL. 51 | * 52 | * @param url the URL for which the cookies are requested 53 | * @return the cookies as a string, using the format of the 'Cookie' HTTP 54 | * header 55 | */ 56 | public String getCookie(final String url) { 57 | return awCookieManager_.getCookie(url); 58 | } 59 | 60 | /** 61 | * Removes all session cookies, which are cookies without an expiration date. 62 | */ 63 | public void removeSessionCookie() { 64 | awCookieManager_.removeSessionCookie(); 65 | } 66 | 67 | /** 68 | * Removes all cookies. 69 | */ 70 | public void removeAllCookie() { 71 | awCookieManager_.removeAllCookie(); 72 | } 73 | 74 | /** 75 | * Gets whether there are stored cookies. 76 | * 77 | * @return true if there are stored cookies 78 | */ 79 | public boolean hasCookies() { 80 | return awCookieManager_.hasCookies(); 81 | } 82 | 83 | /** 84 | * Removes all expired cookies. 85 | */ 86 | public void removeExpiredCookie() { 87 | awCookieManager_.removeExpiredCookie(); 88 | } 89 | 90 | /** 91 | * Gets whether the ChromeView instances send and accept cookies for file 92 | * scheme URLs. 93 | * 94 | * @return true if WebView instances send and accept cookies for file scheme 95 | * URLs 96 | */ 97 | public boolean allowFileSchemeCookies() { 98 | return awCookieManager_.allowFileSchemeCookies(); 99 | } 100 | 101 | /** 102 | * Sets whether the application's WebView instances should send and accept 103 | * cookies for file scheme URLs. Use of cookies with file scheme URLs is 104 | * potentially insecure. Do not use this feature unless you can be sure that 105 | * no unintentional sharing of cookie data can take place. 106 | * 107 | * Note that calls to this method will have no effect if made after a WebView 108 | * or CookieManager instance has been created. 109 | */ 110 | public void setAcceptFileSchemeCookies(boolean accept) { 111 | awCookieManager_.setAcceptFileSchemeCookies(accept); 112 | } 113 | 114 | /** Gets the singleton ChromeCookieManager instance. */ 115 | public synchronized static ChromeCookieManager getInstance() { 116 | if (instance_ == null) { 117 | instance_ = new ChromeCookieManager(); 118 | } 119 | return instance_; 120 | } 121 | private static ChromeCookieManager instance_ = null; 122 | } 123 | -------------------------------------------------------------------------------- /src/us/costan/chrome/ChromeHttpAuthHandler.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome; 2 | 3 | /** 4 | * ChromeView equivalent of HttpAuthHandler. 5 | * 6 | * This is necessary because HttpAuthHandler's constructor is package-private, 7 | * so it is impossible to extend the class, which would have been a cleaner way 8 | * to proxy to AwHttpAuthHandler. 9 | * 10 | * @see android.webkit.HttpAuthHandler 11 | */ 12 | public interface ChromeHttpAuthHandler { 13 | // Mostly mirrors 14 | // platform/frameworks/base/ ./core/java/android/webkit/HttpAuthHandler 15 | 16 | /** 17 | * @return True if we can use user credentials on record 18 | * (ie, if we did not fail trying to use them last time) 19 | */ 20 | public boolean useHttpAuthUsernamePassword(); 21 | 22 | /** 23 | * Cancel the authorization request. 24 | */ 25 | public void cancel(); 26 | 27 | /** 28 | * Proceed with the authorization with the given credentials. 29 | */ 30 | public void proceed(String username, String password); 31 | 32 | /** 33 | * return true if the prompt dialog should be suppressed. 34 | * @hide 35 | */ 36 | public boolean suppressDialog(); 37 | } 38 | -------------------------------------------------------------------------------- /src/us/costan/chrome/ChromeJavascriptInterface.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Marks a method as being able to be exposed to JavaScript. 10 | * 11 | * This is used for safety purposes. Otherwise, the only reasonable behavior 12 | * would be to expose all public methods to JavaScript. 13 | * 14 | * @see {@link ChromeView#addJavascriptInterface(Object, String)} 15 | */ 16 | @SuppressWarnings("javadoc") 17 | @Retention(RetentionPolicy.RUNTIME) 18 | @Target({ElementType.METHOD}) 19 | public @interface ChromeJavascriptInterface { 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/us/costan/chrome/ChromeJsPromptResult.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome; 2 | 3 | /** 4 | * ChromeView equivalent of JsPromptResult. 5 | * 6 | * This is necessary because JsPromptResult.ResultRecever is hidden in the SDK. 7 | * 8 | * @see android.webkit.JsPromptResult 9 | */ 10 | public class ChromeJsPromptResult extends ChromeJsResult { 11 | // Mostly mirrors 12 | // platform/frameworks/base/ ./core/java/android/webkit/JsPromptResult 13 | 14 | // String result of the prompt 15 | private String mStringResult; 16 | 17 | /** 18 | * Handle a confirmation response from the user. 19 | */ 20 | public void confirm(String result) { 21 | mStringResult = result; 22 | confirm(); 23 | } 24 | 25 | /** 26 | * @hide Only for use by WebViewProvider implementations 27 | */ 28 | public ChromeJsPromptResult(ResultReceiver receiver) { 29 | super(receiver); 30 | } 31 | 32 | /** 33 | * @hide Only for use by WebViewProvider implementations 34 | */ 35 | public String getStringResult() { 36 | return mStringResult; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/us/costan/chrome/ChromeJsResult.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome; 2 | 3 | /** 4 | * ChromeView equivalent of JsResult. 5 | * 6 | * This is necessary because JsResult.ResultRecever is hidden in the SDK. 7 | * 8 | * @see android.webkit.JsResult 9 | */ 10 | public class ChromeJsResult { 11 | // Mostly mirrors 12 | // platform/frameworks/base/ ./core/java/android/webkit/JsResult 13 | 14 | /** 15 | * Callback interface, implemented by the WebViewProvider implementation to receive 16 | * notifications when the JavaScript result represented by a JsResult instance has 17 | * @hide Only for use by WebViewProvider implementations 18 | */ 19 | public interface ResultReceiver { 20 | public void onJsResultComplete(ChromeJsResult result); 21 | } 22 | // This is the caller of the prompt and is the object that is waiting. 23 | private final ResultReceiver mReceiver; 24 | // This is a basic result of a confirm or prompt dialog. 25 | private boolean mResult; 26 | 27 | /** 28 | * Handle the result if the user cancelled the dialog. 29 | */ 30 | public final void cancel() { 31 | mResult = false; 32 | wakeUp(); 33 | } 34 | 35 | /** 36 | * Handle a confirmation response from the user. 37 | */ 38 | public final void confirm() { 39 | mResult = true; 40 | wakeUp(); 41 | } 42 | 43 | /** 44 | * @hide Only for use by WebViewProvider implementations 45 | */ 46 | public ChromeJsResult(ResultReceiver receiver) { 47 | mReceiver = receiver; 48 | } 49 | 50 | /** 51 | * @hide Only for use by WebViewProvider implementations 52 | */ 53 | public final boolean getResult() { 54 | return mResult; 55 | } 56 | 57 | /* Notify the caller that the JsResult has completed */ 58 | private final void wakeUp() { 59 | mReceiver.onJsResultComplete(this); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/us/costan/chrome/ChromeSettings.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome; 2 | 3 | import android.webkit.WebSettings.LayoutAlgorithm; 4 | import android.webkit.WebSettings.PluginState; 5 | import android.webkit.WebSettings.RenderPriority; 6 | import android.webkit.WebSettings.ZoomDensity; 7 | 8 | /** 9 | * ChromeView equivalent of WebSettings. 10 | * 11 | * @see android.webkit.WebSettings 12 | */ 13 | public abstract class ChromeSettings { 14 | /** 15 | * Sets whether the WebView should support zooming using its on-screen zoom 16 | * controls and gestures. The particular zoom mechanisms that should be used 17 | * can be set with {@link #setBuiltInZoomControls}. This setting does not 18 | * affect zooming performed using the {@link WebView#zoomIn()} and 19 | * {@link WebView#zoomOut()} methods. The default is true. 20 | * 21 | * @param support whether the WebView should support zoom 22 | */ 23 | public abstract void setSupportZoom(boolean support); 24 | 25 | /** 26 | * Gets whether the WebView supports zoom. 27 | * 28 | * @return true if the WebView supports zoom 29 | * @see #setSupportZoom 30 | */ 31 | public abstract boolean supportZoom(); 32 | 33 | /** 34 | * Sets whether the WebView requires a user gesture to play media. 35 | * The default is true. 36 | * 37 | * @param require whether the WebView requires a user gesture to play media 38 | */ 39 | public abstract void setMediaPlaybackRequiresUserGesture(boolean require); 40 | 41 | /** 42 | * Gets whether the WebView requires a user gesture to play media. 43 | * 44 | * @return true if the WebView requires a user gesture to play media 45 | * @see #setMediaPlaybackRequiresUserGesture 46 | */ 47 | public abstract boolean getMediaPlaybackRequiresUserGesture(); 48 | 49 | /** 50 | * Sets whether the WebView should use its built-in zoom mechanisms. The 51 | * built-in zoom mechanisms comprise on-screen zoom controls, which are 52 | * displayed over the WebView's content, and the use of a pinch gesture to 53 | * control zooming. Whether or not these on-screen controls are displayed 54 | * can be set with {@link #setDisplayZoomControls}. The default is false. 55 | *

56 | * The built-in mechanisms are the only currently supported zoom 57 | * mechanisms, so it is recommended that this setting is always enabled. 58 | * 59 | * @param enabled whether the WebView should use its built-in zoom mechanisms 60 | */ 61 | // This method was intended to select between the built-in zoom mechanisms 62 | // and the separate zoom controls. The latter were obtained using 63 | // {@link WebView#getZoomControls}, which is now hidden. 64 | public abstract void setBuiltInZoomControls(boolean enabled); 65 | 66 | /** 67 | * Gets whether the zoom mechanisms built into WebView are being used. 68 | * 69 | * @return true if the zoom mechanisms built into WebView are being used 70 | * @see #setBuiltInZoomControls 71 | */ 72 | public abstract boolean getBuiltInZoomControls(); 73 | 74 | /** 75 | * Sets whether the WebView should display on-screen zoom controls when 76 | * using the built-in zoom mechanisms. See {@link #setBuiltInZoomControls}. 77 | * The default is true. 78 | * 79 | * @param enabled whether the WebView should display on-screen zoom controls 80 | */ 81 | public abstract void setDisplayZoomControls(boolean enabled); 82 | 83 | /** 84 | * Gets whether the WebView displays on-screen zoom controls when using 85 | * the built-in zoom mechanisms. 86 | * 87 | * @return true if the WebView displays on-screen zoom controls when using 88 | * the built-in zoom mechanisms 89 | * @see #setDisplayZoomControls 90 | */ 91 | public abstract boolean getDisplayZoomControls(); 92 | 93 | /** 94 | * Enables or disables file access within WebView. File access is enabled by 95 | * default. Note that this enables or disables file system access only. 96 | * Assets and resources are still accessible using file:///android_asset and 97 | * file:///android_res. 98 | */ 99 | public abstract void setAllowFileAccess(boolean allow); 100 | 101 | /** 102 | * Gets whether this WebView supports file access. 103 | * 104 | * @see #setAllowFileAccess 105 | */ 106 | public abstract boolean getAllowFileAccess(); 107 | 108 | /** 109 | * Enables or disables content URL access within WebView. Content URL 110 | * access allows WebView to load content from a content provider installed 111 | * in the system. The default is enabled. 112 | */ 113 | public abstract void setAllowContentAccess(boolean allow); 114 | 115 | /** 116 | * Gets whether this WebView supports content URL access. 117 | * 118 | * @see #setAllowContentAccess 119 | */ 120 | public abstract boolean getAllowContentAccess(); 121 | 122 | /** 123 | * Sets whether the WebView loads pages in overview mode. The default is 124 | * false. 125 | */ 126 | public abstract void setLoadWithOverviewMode(boolean overview); 127 | 128 | /** 129 | * Gets whether this WebView loads pages in overview mode. 130 | * 131 | * @return whether this WebView loads pages in overview mode 132 | * @see #setLoadWithOverviewMode 133 | */ 134 | public abstract boolean getLoadWithOverviewMode(); 135 | 136 | /** 137 | * Sets whether the WebView should save form data. The default is true, 138 | * unless in private browsing mode, when the value is always false. 139 | */ 140 | public abstract void setSaveFormData(boolean save); 141 | 142 | /** 143 | * Gets whether the WebView saves form data. Always false in private 144 | * browsing mode. 145 | * 146 | * @return whether the WebView saves form data 147 | * @see #setSaveFormData 148 | */ 149 | public abstract boolean getSaveFormData(); 150 | 151 | /** 152 | * Sets whether the WebView should save passwords. The default is true. 153 | */ 154 | public abstract void setSavePassword(boolean save); 155 | 156 | /** 157 | * Gets whether the WebView saves passwords. 158 | * 159 | * @return whether the WebView saves passwords 160 | * @see #setSavePassword 161 | */ 162 | public abstract boolean getSavePassword(); 163 | 164 | /** 165 | * Sets the text zoom of the page in percent. The default is 100. 166 | * 167 | * @param textZoom the text zoom in percent 168 | */ 169 | public abstract void setTextZoom(int textZoom); 170 | 171 | /** 172 | * Gets the text zoom of the page in percent. 173 | * 174 | * @return the text zoom of the page in percent 175 | * @see #setTextZoom 176 | */ 177 | public abstract int getTextZoom(); 178 | 179 | /** 180 | * Sets the default zoom density of the page. This must be called from the UI 181 | * thread. The default is {@link ZoomDensity#MEDIUM}. 182 | * 183 | * @param zoom the zoom density 184 | */ 185 | public abstract void setDefaultZoom(ZoomDensity zoom); 186 | 187 | /** 188 | * Gets the default zoom density of the page. This should be called from 189 | * the UI thread. 190 | * 191 | * @return the zoom density 192 | * @see #setDefaultZoom 193 | */ 194 | public abstract ZoomDensity getDefaultZoom(); 195 | 196 | /** 197 | * Enables using light touches to make a selection and activate mouseovers. 198 | * The default is false. 199 | */ 200 | public abstract void setLightTouchEnabled(boolean enabled); 201 | 202 | /** 203 | * Gets whether light touches are enabled. 204 | * 205 | * @return whether light touches are enabled 206 | * @see #setLightTouchEnabled 207 | */ 208 | public abstract boolean getLightTouchEnabled(); 209 | 210 | /** 211 | * Tells the WebView to use a wide viewport. The default is false. 212 | * 213 | * @param use whether to use a wide viewport 214 | */ 215 | public abstract void setUseWideViewPort(boolean use); 216 | 217 | /** 218 | * Gets whether the WebView is using a wide viewport. 219 | * 220 | * @return true if the WebView is using a wide viewport 221 | * @see #setUseWideViewPort 222 | */ 223 | public abstract boolean getUseWideViewPort(); 224 | 225 | /** 226 | * Sets whether the WebView whether supports multiple windows. If set to 227 | * true, {@link WebChromeClient#onCreateWindow} must be implemented by the 228 | * host application. The default is false. 229 | * 230 | * @param support whether to suport multiple windows 231 | */ 232 | public abstract void setSupportMultipleWindows(boolean support); 233 | 234 | /** 235 | * Gets whether the WebView supports multiple windows. 236 | * 237 | * @return true if the WebView supports multiple windows 238 | * @see #setSupportMultipleWindows 239 | */ 240 | public abstract boolean supportMultipleWindows(); 241 | 242 | /** 243 | * Sets the underlying layout algorithm. This will cause a relayout of the 244 | * WebView. The default is {@link LayoutAlgorithm#NARROW_COLUMNS}. 245 | * 246 | * @param l the layout algorithm to use, as a {@link LayoutAlgorithm} value 247 | */ 248 | public abstract void setLayoutAlgorithm(LayoutAlgorithm l); 249 | 250 | /** 251 | * Gets the current layout algorithm. 252 | * 253 | * @return the layout algorithm in use, as a {@link LayoutAlgorithm} value 254 | * @see #setLayoutAlgorithm 255 | */ 256 | public abstract LayoutAlgorithm getLayoutAlgorithm(); 257 | 258 | /** 259 | * Sets the standard font family name. The default is "sans-serif". 260 | * 261 | * @param font a font family name 262 | */ 263 | public abstract void setStandardFontFamily(String font); 264 | 265 | /** 266 | * Gets the standard font family name. 267 | * 268 | * @return the standard font family name as a string 269 | * @see #setStandardFontFamily 270 | */ 271 | public abstract String getStandardFontFamily(); 272 | 273 | /** 274 | * Sets the fixed font family name. The default is "monospace". 275 | * 276 | * @param font a font family name 277 | */ 278 | public abstract void setFixedFontFamily(String font); 279 | 280 | /** 281 | * Gets the fixed font family name. 282 | * 283 | * @return the fixed font family name as a string 284 | * @see #setFixedFontFamily 285 | */ 286 | public abstract String getFixedFontFamily(); 287 | 288 | /** 289 | * Sets the sans-serif font family name. The default is "sans-serif". 290 | * 291 | * @param font a font family name 292 | */ 293 | public abstract void setSansSerifFontFamily(String font); 294 | 295 | /** 296 | * Gets the sans-serif font family name. 297 | * 298 | * @return the sans-serif font family name as a string 299 | * @see #setSansSerifFontFamily 300 | */ 301 | public abstract String getSansSerifFontFamily(); 302 | 303 | /** 304 | * Sets the serif font family name. The default is "sans-serif". 305 | * 306 | * @param font a font family name 307 | */ 308 | public abstract void setSerifFontFamily(String font); 309 | 310 | /** 311 | * Gets the serif font family name. The default is "serif". 312 | * 313 | * @return the serif font family name as a string 314 | * @see #setSerifFontFamily 315 | */ 316 | public abstract String getSerifFontFamily(); 317 | 318 | /** 319 | * Sets the cursive font family name. The default is "cursive". 320 | * 321 | * @param font a font family name 322 | */ 323 | public abstract void setCursiveFontFamily(String font); 324 | 325 | /** 326 | * Gets the cursive font family name. 327 | * 328 | * @return the cursive font family name as a string 329 | * @see #setCursiveFontFamily 330 | */ 331 | public abstract String getCursiveFontFamily(); 332 | 333 | /** 334 | * Sets the fantasy font family name. The default is "fantasy". 335 | * 336 | * @param font a font family name 337 | */ 338 | public abstract void setFantasyFontFamily(String font); 339 | 340 | /** 341 | * Gets the fantasy font family name. 342 | * 343 | * @return the fantasy font family name as a string 344 | * @see #setFantasyFontFamily 345 | */ 346 | public abstract String getFantasyFontFamily(); 347 | 348 | /** 349 | * Sets the minimum font size. The default is 8. 350 | * 351 | * @param size a non-negative integer between 1 and 72. Any number outside 352 | * the specified range will be pinned. 353 | */ 354 | public abstract void setMinimumFontSize(int size); 355 | 356 | /** 357 | * Gets the minimum font size. 358 | * 359 | * @return a non-negative integer between 1 and 72 360 | * @see #setMinimumFontSize 361 | */ 362 | public abstract int getMinimumFontSize(); 363 | 364 | /** 365 | * Sets the minimum logical font size. The default is 8. 366 | * 367 | * @param size a non-negative integer between 1 and 72. Any number outside 368 | * the specified range will be pinned. 369 | */ 370 | public abstract void setMinimumLogicalFontSize(int size); 371 | 372 | /** 373 | * Gets the minimum logical font size. 374 | * 375 | * @return a non-negative integer between 1 and 72 376 | * @see #setMinimumLogicalFontSize 377 | */ 378 | public abstract int getMinimumLogicalFontSize(); 379 | 380 | /** 381 | * Sets the default font size. The default is 16. 382 | * 383 | * @param size a non-negative integer between 1 and 72. Any number outside 384 | * the specified range will be pinned. 385 | */ 386 | public abstract void setDefaultFontSize(int size); 387 | 388 | /** 389 | * Gets the default font size. 390 | * 391 | * @return a non-negative integer between 1 and 72 392 | * @see #setDefaultFontSize 393 | */ 394 | public abstract int getDefaultFontSize(); 395 | 396 | /** 397 | * Sets the default fixed font size. The default is 16. 398 | * 399 | * @param size a non-negative integer between 1 and 72. Any number outside 400 | * the specified range will be pinned. 401 | */ 402 | public abstract void setDefaultFixedFontSize(int size); 403 | 404 | /** 405 | * Gets the default fixed font size. 406 | * 407 | * @return a non-negative integer between 1 and 72 408 | * @see #setDefaultFixedFontSize 409 | */ 410 | public abstract int getDefaultFixedFontSize(); 411 | 412 | /** 413 | * Sets whether the WebView should load image resources. Note that this method 414 | * controls loading of all images, including those embedded using the data 415 | * URI scheme. Use {@link #setBlockNetworkImage} to control loading only 416 | * of images specified using network URI schemes. Note that if the value of this 417 | * setting is changed from false to true, all images resources referenced 418 | * by content currently displayed by the WebView are loaded automatically. 419 | * The default is true. 420 | * 421 | * @param flag whether the WebView should load image resources 422 | */ 423 | public abstract void setLoadsImagesAutomatically(boolean flag); 424 | 425 | /** 426 | * Gets whether the WebView loads image resources. This includes 427 | * images embedded using the data URI scheme. 428 | * 429 | * @return true if the WebView loads image resources 430 | * @see #setLoadsImagesAutomatically 431 | */ 432 | public abstract boolean getLoadsImagesAutomatically(); 433 | 434 | /** 435 | * Sets whether the WebView should not load image resources from the 436 | * network (resources accessed via http and https URI schemes). Note 437 | * that this method has no effect unless 438 | * {@link #getLoadsImagesAutomatically} returns true. Also note that 439 | * disabling all network loads using {@link #setBlockNetworkLoads} 440 | * will also prevent network images from loading, even if this flag is set 441 | * to false. When the value of this setting is changed from true to false, 442 | * network images resources referenced by content currently displayed by 443 | * the WebView are fetched automatically. The default is false. 444 | * 445 | * @param flag whether the WebView should not load image resources from the 446 | * network 447 | * @see #setBlockNetworkLoads 448 | */ 449 | public abstract void setBlockNetworkImage(boolean flag); 450 | 451 | /** 452 | * Gets whether the WebView does not load image resources from the network. 453 | * 454 | * @return true if the WebView does not load image resources from the network 455 | * @see #setBlockNetworkImage 456 | */ 457 | public abstract boolean getBlockNetworkImage(); 458 | 459 | /** 460 | * Sets whether the WebView should not load resources from the network. 461 | * Use {@link #setBlockNetworkImage} to only avoid loading 462 | * image resources. Note that if the value of this setting is 463 | * changed from true to false, network resources referenced by content 464 | * currently displayed by the WebView are not fetched until 465 | * {@link android.webkit.WebView#reload} is called. 466 | * If the application does not have the 467 | * {@link android.Manifest.permission#INTERNET} permission, attempts to set 468 | * a value of false will cause a {@link java.lang.SecurityException} 469 | * to be thrown. The default value is false if the application has the 470 | * {@link android.Manifest.permission#INTERNET} permission, otherwise it is 471 | * true. 472 | * 473 | * @param flag whether the WebView should not load any resources from the 474 | * network 475 | * @see android.webkit.WebView#reload 476 | */ 477 | public abstract void setBlockNetworkLoads(boolean flag); 478 | 479 | /** 480 | * Gets whether the WebView does not load any resources from the network. 481 | * 482 | * @return true if the WebView does not load any resources from the network 483 | * @see #setBlockNetworkLoads 484 | */ 485 | public abstract boolean getBlockNetworkLoads(); 486 | 487 | /** 488 | * Tells the WebView to enable JavaScript execution. 489 | * The default is false. 490 | * 491 | * @param flag true if the WebView should execute JavaScript 492 | */ 493 | public abstract void setJavaScriptEnabled(boolean flag); 494 | 495 | /** 496 | * Sets whether JavaScript running in the context of a file scheme URL 497 | * should be allowed to access content from any origin. This includes 498 | * access to content from other file scheme URLs. See 499 | * {@link #setAllowFileAccessFromFileURLs}. To enable the most restrictive, 500 | * and therefore secure policy, this setting should be disabled. 501 | *

502 | * The default value is true for API level 503 | * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below, 504 | * and false for API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN} 505 | * and above. 506 | * 507 | * @param flag whether JavaScript running in the context of a file scheme 508 | * URL should be allowed to access content from any origin 509 | */ 510 | public abstract void setAllowUniversalAccessFromFileURLs(boolean flag); 511 | 512 | /** 513 | * Sets whether JavaScript running in the context of a file scheme URL 514 | * should be allowed to access content from other file scheme URLs. To 515 | * enable the most restrictive, and therefore secure policy, this setting 516 | * should be disabled. Note that the value of this setting is ignored if 517 | * the value of {@link #getAllowUniversalAccessFromFileURLs} is true. 518 | *

519 | * The default value is true for API level 520 | * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below, 521 | * and false for API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN} 522 | * and above. 523 | * 524 | * @param flag whether JavaScript running in the context of a file scheme 525 | * URL should be allowed to access content from other file 526 | * scheme URLs 527 | */ 528 | public abstract void setAllowFileAccessFromFileURLs(boolean flag); 529 | 530 | /** 531 | * Tells the WebView to enable, disable, or have plugins on demand. On 532 | * demand mode means that if a plugin exists that can handle the embedded 533 | * content, a placeholder icon will be shown instead of the plugin. When 534 | * the placeholder is clicked, the plugin will be enabled. The default is 535 | * {@link PluginState#OFF}. 536 | * 537 | * @param state a PluginState value 538 | */ 539 | public abstract void setPluginState(PluginState state); 540 | 541 | /** 542 | * Sets the path to where database storage API databases should be saved. 543 | * In order for the database storage API to function correctly, this method 544 | * must be called with a path to which the application can write. This 545 | * method should only be called once: repeated calls are ignored. 546 | * 547 | * @param databasePath a path to the directory where databases should be 548 | * saved. 549 | */ 550 | // This will update WebCore when the Sync runs in the C++ side. 551 | // Note that the WebCore Database Tracker only allows the path to be set 552 | // once. 553 | public abstract void setDatabasePath(String databasePath); 554 | 555 | /** 556 | * Sets the path where the Geolocation databases should be saved. In order 557 | * for Geolocation permissions and cached positions to be persisted, this 558 | * method must be called with a path to which the application can write. 559 | * 560 | * @param databasePath a path to the directory where databases should be 561 | * saved. 562 | */ 563 | // This will update WebCore when the Sync runs in the C++ side. 564 | public abstract void setGeolocationDatabasePath(String databasePath); 565 | 566 | /** 567 | * Sets whether the Application Caches API should be enabled. The default 568 | * is false. Note that in order for the Application Caches API to be 569 | * enabled, a valid database path must also be supplied to 570 | * {@link #setAppCachePath}. 571 | * 572 | * @param flag true if the WebView should enable Application Caches 573 | */ 574 | public abstract void setAppCacheEnabled(boolean flag); 575 | 576 | /** 577 | * Sets the path to the Application Caches files. In order for the 578 | * Application Caches API to be enabled, this method must be called with a 579 | * path to which the application can write. This method should only be 580 | * called once: repeated calls are ignored. 581 | * 582 | * @param appCachePath a String path to the directory containing 583 | * Application Caches files. 584 | * @see setAppCacheEnabled 585 | */ 586 | public abstract void setAppCachePath(String appCachePath); 587 | 588 | /** 589 | * Sets the maximum size for the Application Cache content. The passed size 590 | * will be rounded to the nearest value that the database can support, so 591 | * this should be viewed as a guide, not a hard limit. Setting the 592 | * size to a value less than current database size does not cause the 593 | * database to be trimmed. The default size is {@link Long#MAX_VALUE}. 594 | * 595 | * @param appCacheMaxSize the maximum size in bytes 596 | */ 597 | public abstract void setAppCacheMaxSize(long appCacheMaxSize); 598 | 599 | /** 600 | * Sets whether the database storage API is enabled. The default value is 601 | * false. See also {@link #setDatabasePath} for how to correctly set up the 602 | * database storage API. 603 | * 604 | * @param flag true if the WebView should use the database storage API 605 | */ 606 | public abstract void setDatabaseEnabled(boolean flag); 607 | 608 | /** 609 | * Sets whether the DOM storage API is enabled. The default value is false. 610 | * 611 | * @param flag true if the WebView should use the DOM storage API 612 | */ 613 | public abstract void setDomStorageEnabled(boolean flag); 614 | 615 | /** 616 | * Gets whether the DOM Storage APIs are enabled. 617 | * 618 | * @return true if the DOM Storage APIs are enabled 619 | * @see #setDomStorageEnabled 620 | */ 621 | public abstract boolean getDomStorageEnabled(); 622 | /** 623 | * Gets the path to where database storage API databases are saved. 624 | * 625 | * @return the String path to the database storage API databases 626 | * @see #setDatabasePath 627 | */ 628 | public abstract String getDatabasePath(); 629 | 630 | /** 631 | * Gets whether the database storage API is enabled. 632 | * 633 | * @return true if the database storage API is enabled 634 | * @see #setDatabaseEnabled 635 | */ 636 | public abstract boolean getDatabaseEnabled(); 637 | 638 | /** 639 | * Sets whether Geolocation is enabled. The default is true. See also 640 | * {@link #setGeolocationDatabasePath} for how to correctly set up 641 | * Geolocation. 642 | * 643 | * @param flag whether Geolocation should be enabled 644 | */ 645 | public abstract void setGeolocationEnabled(boolean flag); 646 | 647 | /** 648 | * Gets whether JavaScript is enabled. 649 | * 650 | * @return true if JavaScript is enabled 651 | * @see #setJavaScriptEnabled 652 | */ 653 | public abstract boolean getJavaScriptEnabled(); 654 | 655 | /** 656 | * Gets whether JavaScript running in the context of a file scheme URL can 657 | * access content from any origin. This includes access to content from 658 | * other file scheme URLs. 659 | * 660 | * @return whether JavaScript running in the context of a file scheme URL 661 | * can access content from any origin 662 | * @see #setAllowUniversalAccessFromFileURLs 663 | */ 664 | public abstract boolean getAllowUniversalAccessFromFileURLs(); 665 | 666 | /** 667 | * Gets whether JavaScript running in the context of a file scheme URL can 668 | * access content from other file scheme URLs. 669 | * 670 | * @return whether JavaScript running in the context of a file scheme URL 671 | * can access content from other file scheme URLs 672 | * @see #setAllowFileAccessFromFileURLs 673 | */ 674 | public abstract boolean getAllowFileAccessFromFileURLs(); 675 | 676 | /** 677 | * Gets the current state regarding whether plugins are enabled. 678 | * 679 | * @return the plugin state as a {@link PluginState} value 680 | * @see #setPluginState 681 | */ 682 | public abstract PluginState getPluginState(); 683 | 684 | /** 685 | * Tells JavaScript to open windows automatically. This applies to the 686 | * JavaScript function window.open(). The default is false. 687 | * 688 | * @param flag true if JavaScript can open windows automatically 689 | */ 690 | public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean flag); 691 | 692 | /** 693 | * Gets whether JavaScript can open windows automatically. 694 | * 695 | * @return true if JavaScript can open windows automatically during 696 | * window.open() 697 | * @see #setJavaScriptCanOpenWindowsAutomatically 698 | */ 699 | public abstract boolean getJavaScriptCanOpenWindowsAutomatically(); 700 | /** 701 | * Sets the default text encoding name to use when decoding html pages. 702 | * The default is "Latin-1". 703 | * 704 | * @param encoding the text encoding name 705 | */ 706 | public abstract void setDefaultTextEncodingName(String encoding); 707 | 708 | /** 709 | * Gets the default text encoding name. 710 | * 711 | * @return the default text encoding name as a string 712 | * @see #setDefaultTextEncodingName 713 | */ 714 | public abstract String getDefaultTextEncodingName(); 715 | 716 | /** 717 | * Sets the WebView's user-agent string. If the string is null or empty, 718 | * the system default value will be used. 719 | */ 720 | public abstract void setUserAgentString(String ua); 721 | 722 | /** 723 | * Gets the WebView's user-agent string. 724 | * 725 | * @return the WebView's user-agent string 726 | * @see #setUserAgentString 727 | */ 728 | public abstract String getUserAgentString(); 729 | 730 | /** 731 | * Tells the WebView whether it needs to set a node to have focus when 732 | * {@link WebView#requestFocus(int, android.graphics.Rect)} is called. The 733 | * default value is true. 734 | * 735 | * @param flag whether the WebView needs to set a node 736 | */ 737 | public abstract void setNeedInitialFocus(boolean flag); 738 | 739 | /** 740 | * Sets the priority of the Render thread. Unlike the other settings, this 741 | * one only needs to be called once per process. The default value is 742 | * {@link RenderPriority#NORMAL}. 743 | * 744 | * @param priority the priority 745 | */ 746 | public abstract void setRenderPriority(RenderPriority priority); 747 | 748 | /** 749 | * Overrides the way the cache is used. The way the cache is used is based 750 | * on the navigation type. For a normal page load, the cache is checked 751 | * and content is re-validated as needed. When navigating back, content is 752 | * not revalidated, instead the content is just retrieved from the cache. 753 | * This method allows the client to override this behavior by specifying 754 | * one of {@link #LOAD_DEFAULT}, {@link #LOAD_NORMAL}, 755 | * {@link #LOAD_CACHE_ELSE_NETWORK}, {@link #LOAD_NO_CACHE} or 756 | * {@link #LOAD_CACHE_ONLY}. The default value is {@link #LOAD_DEFAULT}. 757 | * 758 | * @param mode the mode to use 759 | */ 760 | public abstract void setCacheMode(int mode); 761 | 762 | /** 763 | * Gets the current setting for overriding the cache mode. 764 | * 765 | * @return the current setting for overriding the cache mode 766 | * @see #setCacheMode 767 | */ 768 | public abstract int getCacheMode(); 769 | } 770 | -------------------------------------------------------------------------------- /src/us/costan/chrome/ChromeSslErrorHandler.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome; 2 | 3 | /** 4 | * ChromeView equivalent of SslErrorHandler. 5 | * 6 | * This is necessary because SslErrorHandler's constructor is package-private, 7 | * so it is impossible to extend the class, which would have been cleaner. 8 | * 9 | * @see android.webkit.SslErrorHandler 10 | */ 11 | public interface ChromeSslErrorHandler { 12 | // Mostly mirrors 13 | // platform/frameworks/base/ ./core/java/android/webkit/SslErrorHandler 14 | /** 15 | * Proceed with the SSL certificate. 16 | */ 17 | public void proceed(); 18 | 19 | /** 20 | * Cancel this request and all pending requests for the WebView that had 21 | * the error. 22 | */ 23 | public void cancel(); 24 | } 25 | -------------------------------------------------------------------------------- /src/us/costan/chrome/ChromeView.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome; 2 | 3 | import java.util.Map; 4 | 5 | import org.chromium.android_webview.AwBrowserContext; 6 | import org.chromium.android_webview.AwContents; 7 | import org.chromium.content.browser.ContentViewCore; 8 | import org.chromium.content.browser.ContentViewStatics; 9 | import org.chromium.content.browser.LoadUrlParams; 10 | import org.chromium.content.browser.ContentViewCore.JavaScriptCallback; 11 | 12 | import us.costan.chrome.impl.ChromeAwContentsClientProxy; 13 | import us.costan.chrome.impl.ChromeInitializer; 14 | import us.costan.chrome.impl.ChromeSettingsProxy; 15 | import android.annotation.SuppressLint; 16 | import android.annotation.TargetApi; 17 | import android.app.Activity; 18 | import android.content.Context; 19 | import android.content.SharedPreferences; 20 | import android.content.res.Configuration; 21 | import android.graphics.Bitmap; 22 | import android.graphics.Canvas; 23 | import android.graphics.Picture; 24 | import android.graphics.Rect; 25 | import android.net.http.SslCertificate; 26 | import android.os.Build; 27 | import android.os.Bundle; 28 | import android.os.Message; 29 | import android.util.AttributeSet; 30 | import android.view.KeyEvent; 31 | import android.view.MotionEvent; 32 | import android.view.View; 33 | import android.view.WindowManager; 34 | import android.view.accessibility.AccessibilityEvent; 35 | import android.view.accessibility.AccessibilityNodeInfo; 36 | import android.view.inputmethod.EditorInfo; 37 | import android.view.inputmethod.InputConnection; 38 | import android.webkit.DownloadListener; 39 | import android.webkit.ValueCallback; 40 | import android.webkit.WebSettings; 41 | import android.webkit.WebView.FindListener; 42 | import android.widget.FrameLayout; 43 | 44 | /** WebView-like layer. */ 45 | public class ChromeView extends FrameLayout { 46 | /** The closest thing to a WebView that Chromium has to offer. */ 47 | private AwContents awContents_; 48 | 49 | /** Implements some of AwContents. */ 50 | private ContentViewCore contentViewCore_; 51 | 52 | /** Glue that passes calls from the Chromium view to a WebChromeClient. */ 53 | private ChromeAwContentsClientProxy awContentsClient_; 54 | 55 | /** Everything pertaining to the user's browsing session. */ 56 | private AwBrowserContext browserContext_; 57 | 58 | /** Glue that passes calls from the Chromium view to its parent (us). */ 59 | private ChromeInternalAcccessAdapter internalAccessAdapter_; 60 | 61 | public ChromeView(Context context) { 62 | this(context, null); 63 | } 64 | 65 | /** Constructor for inflating via XML. */ 66 | public ChromeView(Context context, AttributeSet attrs) { 67 | super(context, attrs, android.R.attr.webViewStyle); 68 | 69 | if (isInEditMode()) { 70 | return; // Chromium isn't loaded in edit mode. 71 | } 72 | 73 | try { 74 | Activity activity = (Activity)context; 75 | activity.getWindow().setFlags( 76 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, 77 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); 78 | 79 | } catch(ClassCastException e) { 80 | // Hope that hardware acceleration is enabled. 81 | } 82 | 83 | SharedPreferences sharedPreferences = context.getSharedPreferences( 84 | "chromeview", Context.MODE_PRIVATE); 85 | // TODO(pwnall): is there a better way to get an AwBrowserContext? 86 | browserContext_ = new AwBrowserContext(sharedPreferences); 87 | 88 | internalAccessAdapter_ = new ChromeView.ChromeInternalAcccessAdapter(); 89 | awContentsClient_ = new ChromeAwContentsClientProxy(this); 90 | awContents_ = new AwContents(browserContext_, this, internalAccessAdapter_, 91 | awContentsClient_, true); 92 | contentViewCore_ = awContents_.getContentViewCore(); 93 | } 94 | 95 | //// Non-WebView extensions 96 | 97 | /** 98 | * Injects the passed Javascript code in the current page and evaluates it. 99 | * If a result is required, pass in a callback. 100 | * Used in automation tests. 101 | * 102 | * @param script The Javascript to execute. 103 | * @param message The callback to be fired off when a result is ready. The script's 104 | * result will be json encoded and passed as the parameter, and the call 105 | * will be made on the main thread. 106 | * If no result is required, pass null. 107 | * @throws IllegalStateException If the ContentView has been destroyed. 108 | */ 109 | public void evaluateJavaScript(String script, JavaScriptCallback callback) { 110 | if (awContents_ != null) { 111 | contentViewCore_.evaluateJavaScript(script, callback); 112 | } 113 | } 114 | 115 | //// WebView methods 116 | 117 | /** 118 | * Return the first substring consisting of the address of a physical 119 | * location. Currently, only addresses in the United States are detected, 120 | * and consist of: 121 | * - a house number 122 | * - a street name 123 | * - a street type (Road, Circle, etc), either spelled out or abbreviated 124 | * - a city name 125 | * - a state or territory, either spelled out or two-letter abbr. 126 | * - an optional 5 digit or 9 digit zip code. 127 | * 128 | * All names must be correctly capitalized, and the zip code, if present, 129 | * must be valid for the state. The street type must be a standard USPS 130 | * spelling or abbreviation. The state or territory must also be spelled 131 | * or abbreviated using USPS standards. The house number may not exceed 132 | * five digits. 133 | * @param addr The string to search for addresses. 134 | * 135 | * @return the address, or if no address is found, return null. 136 | */ 137 | public static String findAddress(String addr) { 138 | return ContentViewStatics.findAddress(addr); 139 | } 140 | 141 | /** 142 | * Sets the ChromeViewClient associated with this view. 143 | * 144 | * @param chromeViewClient the new handler; replaces the old handler 145 | * @see android.webkit.WebView#setWebViewClient(android.webkit.WebViewClient) 146 | * @see android.webkit.WebViewClient 147 | */ 148 | public void setChromeViewClient(ChromeViewClient chromeViewClient) { 149 | awContentsClient_.setChromeViewClient(chromeViewClient); 150 | } 151 | 152 | /** 153 | * Sets the ChromeWebClient associated with this view. 154 | * 155 | * @param chromeWebClient the new handler; replaces the old handler 156 | * @see android.webkit.WebView#setWebChromeClient(android.webkit.WebChromeClient) 157 | * @see android.webkit.WebChromeClient 158 | */ 159 | public void setChromeWebClient(ChromeWebClient chromeWebClient) { 160 | awContentsClient_.setChromeWebClient(chromeWebClient); 161 | } 162 | 163 | /** 164 | * Sets the DownloadListener associated with this view. 165 | * 166 | * @param downloadListener the new listener; replaces the old listener 167 | * @see android.webkit.WebView#setDownloadListener(DownloadListener) 168 | */ 169 | public void setDownloadListener(DownloadListener downloadListener) { 170 | awContentsClient_.setDownloadListener(downloadListener); 171 | } 172 | 173 | /** 174 | * Sets the FindListener associated with this view. 175 | * 176 | * @param findListener the new listener; replaces the old listener 177 | * @see android.webkit.WebView#setFindListener(FindListener) 178 | */ 179 | public void setFindListener(FindListener findListener) { 180 | awContentsClient_.setFindListener(findListener); 181 | } 182 | 183 | /** 184 | * Gets the SSL certificate for the main top-level page or null if there is 185 | * no certificate (the site is not secure). 186 | * 187 | * @return the SSL certificate for the main top-level page 188 | */ 189 | public SslCertificate getCertificate() { 190 | return awContents_.getCertificate(); 191 | } 192 | 193 | /** 194 | * Stores HTTP authentication credentials for a given host and realm. This 195 | * method is intended to be used with 196 | * {@link ChromeViewClient#onReceivedHttpAuthRequest(ChromeView, ChromeHttpAuthHandler, String, String)} 197 | * 198 | * @param host the host to which the credentials apply 199 | * @param realm the realm to which the credentials apply 200 | * @param username the username 201 | * @param password the password 202 | * @see getHttpAuthUsernamePassword 203 | * @see android.webkit.WebViewDatabase#hasHttpAuthUsernamePassword() 204 | * @see android.webkit.WebViewDatabase#clearHttpAuthUsernamePassword() 205 | */ 206 | public void setHttpAuthUsernamePassword(String host, String realm, 207 | String username, String password) { 208 | awContents_.setHttpAuthUsernamePassword(host, realm, username, password); 209 | } 210 | 211 | /** 212 | * Retrieves HTTP authentication credentials for a given host and realm. 213 | * This method is intended to be used with 214 | * {@link ChromeViewClient#onReceivedHttpAuthRequest(ChromeView, ChromeHttpAuthHandler, String, String)}. 215 | * 216 | * @param host the host to which the credentials apply 217 | * @param realm the realm to which the credentials apply 218 | * @return the credentials as a String array, if found. The first element 219 | * is the username and the second element is the password. Null if no 220 | * credentials are found. 221 | * @see setHttpAuthUsernamePassword 222 | * @see android.webkit.WebViewDatabase#hasHttpAuthUsernamePassword() 223 | * @see android.webkit.WebViewDatabase#clearHttpAuthUsernamePassword() 224 | */ 225 | public String[] getHttpAuthUsernamePassword(String host, String realm) { 226 | return awContents_.getHttpAuthUsernamePassword(host, realm); 227 | } 228 | 229 | /** 230 | * Saves the state of this WebView used in 231 | * {@link android.app.Activity#onSaveInstanceState}. Please note that this 232 | * method no longer stores the display data for this WebView. The previous 233 | * behavior could potentially leak files if {@link #restoreState} was never 234 | * called. 235 | * 236 | * @param outState the Bundle to store this WebView's state 237 | * @return false if saveState fails 238 | */ 239 | public boolean saveState(Bundle outState) { 240 | return awContents_.saveState(outState); 241 | } 242 | 243 | /** 244 | * Restores the state of this WebView from the given Bundle. This method is 245 | * intended for use in {@link android.app.Activity#onRestoreInstanceState} 246 | * and should be called to restore the state of this WebView. If 247 | * it is called after this WebView has had a chance to build state (load 248 | * pages, create a back/forward list, etc.) there may be undesirable 249 | * side-effects. Please note that this method no longer restores the 250 | * display data for this WebView. 251 | * 252 | * @param inState the incoming Bundle of state 253 | * @return false if restoreState failed 254 | */ 255 | public boolean restoreState(Bundle inState) { 256 | return awContents_.restoreState(inState); 257 | } 258 | 259 | /** 260 | * Loads the given URL with the specified additional HTTP headers. 261 | * 262 | * @param url the URL of the resource to load 263 | * @param additionalHttpHeaders the additional headers to be used in the 264 | * HTTP request for this URL, specified as a map from name to 265 | * value. Note that if this map contains any of the headers 266 | * that are set by default by this WebView, such as those 267 | * controlling caching, accept types or the User-Agent, their 268 | * values may be overriden by this WebView's defaults. 269 | */ 270 | public void loadUrl(String url, Map additionalHttpHeaders) { 271 | LoadUrlParams loadUrlParams = new LoadUrlParams(url); 272 | loadUrlParams.setExtraHeaders(additionalHttpHeaders); 273 | awContents_.loadUrl(loadUrlParams); 274 | } 275 | 276 | /** 277 | * Loads the given URL. 278 | * 279 | * @param url the URL of the resource to load 280 | */ 281 | public void loadUrl(String url) { 282 | awContents_.loadUrl(new LoadUrlParams(url)); 283 | } 284 | 285 | /** 286 | * Loads the URL with postData using "POST" method into this WebView. If url 287 | * is not a network URL, it will be loaded with {link 288 | * {@link #loadUrl(String)} instead. 289 | * 290 | * @param url the URL of the resource to load 291 | * @param postData the data will be passed to "POST" request 292 | */ 293 | public void postUrl(String url, byte[] postData) { 294 | awContents_.loadUrl(LoadUrlParams.createLoadHttpPostParams(url, postData)); 295 | } 296 | 297 | /** 298 | * Loads the given data into this WebView using a 'data' scheme URL. 299 | *

300 | * Note that JavaScript's same origin policy means that script running in a 301 | * page loaded using this method will be unable to access content loaded 302 | * using any scheme other than 'data', including 'http(s)'. To avoid this 303 | * restriction, use {@link 304 | * #loadDataWithBaseURL(String,String,String,String,String) 305 | * loadDataWithBaseURL()} with an appropriate base URL. 306 | *

307 | * The encoding parameter specifies whether the data is base64 or URL 308 | * encoded. If the data is base64 encoded, the value of the encoding 309 | * parameter must be 'base64'. For all other values of the parameter, 310 | * including null, it is assumed that the data uses ASCII encoding for 311 | * octets inside the range of safe URL characters and use the standard %xx 312 | * hex encoding of URLs for octets outside that range. For example, '#', 313 | * '%', '\', '?' should be replaced by %23, %25, %27, %3f respectively. 314 | *

315 | * The 'data' scheme URL formed by this method uses the default US-ASCII 316 | * charset. If you need need to set a different charset, you should form a 317 | * 'data' scheme URL which explicitly specifies a charset parameter in the 318 | * mediatype portion of the URL and call {@link #loadUrl(String)} instead. 319 | * Note that the charset obtained from the mediatype portion of a data URL 320 | * always overrides that specified in the HTML or XML document itself. 321 | * 322 | * @param data a String of data in the given encoding 323 | * @param mimeType the MIME type of the data, e.g. 'text/html' 324 | * @param encoding the encoding of the data 325 | */ 326 | public void loadData(String data, String mimeType, String encoding) { 327 | LoadUrlParams loadUrlParams = LoadUrlParams.createLoadDataParams(data, 328 | mimeType, encoding.equals("base64")); 329 | awContents_.loadUrl(loadUrlParams); 330 | } 331 | 332 | /** 333 | * Loads the given data into this WebView, using baseUrl as the base URL for 334 | * the content. The base URL is used both to resolve relative URLs and when 335 | * applying JavaScript's same origin policy. The historyUrl is used for the 336 | * history entry. 337 | *

338 | * Note that content specified in this way can access local device files 339 | * (via 'file' scheme URLs) only if baseUrl specifies a scheme other than 340 | * 'http', 'https', 'ftp', 'ftps', 'about' or 'javascript'. 341 | *

342 | * If the base URL uses the data scheme, this method is equivalent to 343 | * calling {@link #loadData(String,String,String) loadData()} and the 344 | * historyUrl is ignored. 345 | * 346 | * @param baseUrl the URL to use as the page's base URL. If null defaults to 347 | * 'about:blank'. 348 | * @param data a String of data in the given encoding 349 | * @param mimeType the MIMEType of the data, e.g. 'text/html'. If null, 350 | * defaults to 'text/html'. 351 | * @param encoding the encoding of the data 352 | * @param historyUrl the URL to use as the history entry. If null defaults 353 | * to 'about:blank'. 354 | */ 355 | public void loadDataWithBaseURL(String baseUrl, String data, 356 | String mimeType, String encoding, String historyUrl) { 357 | LoadUrlParams loadUrlParams = 358 | LoadUrlParams.createLoadDataParamsWithBaseUrl(data, mimeType, 359 | encoding.equals("base64"), baseUrl, historyUrl); 360 | awContents_.loadUrl(loadUrlParams); 361 | } 362 | 363 | /** 364 | * Saves the current view as a web archive. 365 | * 366 | * @param filename the filename where the archive should be placed 367 | */ 368 | public void saveWebArchive(String filename) { 369 | ValueCallback callback = new ValueCallback() { 370 | @Override 371 | public void onReceiveValue(String value) { } 372 | }; 373 | awContents_.saveWebArchive(filename, false, callback); 374 | } 375 | 376 | /** 377 | * Saves the current view as a web archive. 378 | * 379 | * @param basename the filename where the archive should be placed 380 | * @param autoname if false, takes basename to be a file. If true, basename 381 | * is assumed to be a directory in which a filename will be 382 | * chosen according to the URL of the current page. 383 | * @param callback called after the web archive has been saved. The 384 | * parameter for onReceiveValue will either be the filename 385 | * under which the file was saved, or null if saving the 386 | * file failed. 387 | */ 388 | public void saveWebArchive(String basename, boolean autoname, 389 | ValueCallback callback) { 390 | awContents_.saveWebArchive(basename, autoname, callback); 391 | } 392 | 393 | /** 394 | * Stops the current load. 395 | */ 396 | public void stopLoading() { 397 | awContents_.stopLoading(); 398 | } 399 | 400 | /** 401 | * Reloads the current URL. 402 | */ 403 | public void reload() { 404 | awContents_.reload(); 405 | } 406 | 407 | /** 408 | * Gets whether this WebView has a back history item. 409 | * 410 | * @return true iff this WebView has a back history item 411 | */ 412 | public boolean canGoBack() { 413 | return awContents_.canGoBack(); 414 | } 415 | 416 | /** 417 | * Goes back in the history of this WebView. 418 | */ 419 | public void goBack() { 420 | awContents_.goBack(); 421 | } 422 | 423 | /** 424 | * Gets whether this WebView has a forward history item. 425 | * 426 | * @return true iff this Webview has a forward history item 427 | */ 428 | public boolean canGoForward() { 429 | return awContents_.canGoForward(); 430 | } 431 | 432 | /** 433 | * Goes forward in the history of this WebView. 434 | */ 435 | public void goForward() { 436 | awContents_.goForward(); 437 | } 438 | 439 | /** 440 | * Gets whether the page can go back or forward the given 441 | * number of steps. 442 | * 443 | * @param steps the negative or positive number of steps to move the 444 | * history 445 | */ 446 | public boolean canGoBackOrForward(int steps) { 447 | return awContents_.canGoBackOrForward(steps); 448 | } 449 | 450 | /** 451 | * Goes to the history item that is the number of steps away from 452 | * the current item. Steps is negative if backward and positive 453 | * if forward. 454 | * 455 | * @param steps the number of steps to take back or forward in the back 456 | * forward list 457 | */ 458 | public void goBackOrForward(int steps) { 459 | awContents_.goBackOrForward(steps); 460 | } 461 | 462 | /** 463 | * Gets whether private browsing is enabled in this WebView. 464 | */ 465 | public boolean isPrivateBrowsingEnabled() { 466 | return false; 467 | } 468 | 469 | /** 470 | * Scrolls the contents of this WebView up by half the view size. 471 | * 472 | * @param top true to jump to the top of the page 473 | * @return true if the page was scrolled 474 | */ 475 | public boolean pageUp(boolean top) { 476 | return awContents_.pageUp(top); 477 | } 478 | 479 | /** 480 | * Scrolls the contents of this WebView down by half the page size. 481 | * 482 | * @param bottom true to jump to bottom of page 483 | * @return true if the page was scrolled 484 | */ 485 | public boolean pageDown(boolean bottom) { 486 | return awContents_.pageDown(bottom); 487 | } 488 | 489 | /** 490 | * Gets a new picture that captures the current contents of this WebView. 491 | * The picture is of the entire document being displayed, and is not 492 | * limited to the area currently displayed by this WebView. Also, the 493 | * picture is a static copy and is unaffected by later changes to the 494 | * content being displayed. 495 | *

496 | * Note that due to internal changes, for API levels between 497 | * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and 498 | * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} inclusive, the 499 | * picture does not include fixed position elements or scrollable divs. 500 | * 501 | * @return a picture that captures the current contents of this WebView 502 | */ 503 | public Picture capturePicture() { 504 | return awContents_.capturePicture(); 505 | } 506 | 507 | /** 508 | * Sets the initial scale for this WebView. 0 means default. If 509 | * {@link WebSettings#getUseWideViewPort()} is true, it zooms out all the 510 | * way. Otherwise it starts with 100%. If initial scale is greater than 0, 511 | * WebView starts with this value as initial scale. 512 | * Please note that unlike the scale properties in the viewport meta tag, 513 | * this method doesn't take the screen density into account. 514 | * 515 | * @param scaleInPercent the initial scale in percent 516 | */ 517 | public void setInitialScale(int scaleInPercent) { 518 | // TODO(pwnall): seems useful 519 | } 520 | 521 | /** 522 | * Invokes the graphical zoom picker widget for this WebView. This will 523 | * result in the zoom widget appearing on the screen to control the zoom 524 | * level of this WebView. 525 | */ 526 | public void invokeZoomPicker() { 527 | awContents_.invokeZoomPicker(); 528 | } 529 | 530 | /** 531 | * Requests the anchor or image element URL at the last tapped point. 532 | * If hrefMsg is null, this method returns immediately and does not 533 | * dispatch hrefMsg to its target. If the tapped point hits an image, 534 | * an anchor, or an image in an anchor, the message associates 535 | * strings in named keys in its data. The value paired with the key 536 | * may be an empty string. 537 | * 538 | * @param hrefMsg the message to be dispatched with the result of the 539 | * request. The message data contains three keys. "url" 540 | * returns the anchor's href attribute. "title" returns the 541 | * anchor's text. "src" returns the image's src attribute. 542 | */ 543 | public void requestFocusNodeHref(Message hrefMsg) { 544 | awContents_.requestFocusNodeHref(hrefMsg); 545 | } 546 | 547 | /** 548 | * Requests the URL of the image last touched by the user. msg will be sent 549 | * to its target with a String representing the URL as its object. 550 | * 551 | * @param msg the message to be dispatched with the result of the request 552 | * as the data member with "url" as key. The result can be null. 553 | */ 554 | public void requestImageRef(Message msg) { 555 | awContents_.requestImageRef(msg); 556 | } 557 | 558 | /** 559 | * Gets the URL for the current page. This is not always the same as the URL 560 | * passed to WebViewClient.onPageStarted because although the load for 561 | * that URL has begun, the current page may not have changed. 562 | * 563 | * @return the URL for the current page 564 | */ 565 | public String getUrl() { 566 | return awContents_.getUrl(); 567 | } 568 | 569 | /** 570 | * Gets the original URL for the current page. This is not always the same 571 | * as the URL passed to WebViewClient.onPageStarted because although the 572 | * load for that URL has begun, the current page may not have changed. 573 | * Also, there may have been redirects resulting in a different URL to that 574 | * originally requested. 575 | * 576 | * @return the URL that was originally requested for the current page 577 | */ 578 | public String getOriginalUrl() { 579 | return awContents_.getOriginalUrl(); 580 | } 581 | 582 | /** 583 | * Gets the title for the current page. This is the title of the current page 584 | * until WebViewClient.onReceivedTitle is called. 585 | * 586 | * @return the title for the current page 587 | */ 588 | public String getTitle() { 589 | return awContents_.getTitle(); 590 | } 591 | 592 | /** 593 | * Gets the favicon for the current page. This is the favicon of the current 594 | * page until WebViewClient.onReceivedIcon is called. 595 | * 596 | * @return the favicon for the current page 597 | */ 598 | public Bitmap getFavicon() { 599 | return awContents_.getFavicon(); 600 | } 601 | 602 | /** 603 | * Gets the height of the HTML content. 604 | * 605 | * @return the height of the HTML content 606 | */ 607 | public int getContentHeight() { 608 | return awContents_.getContentHeightCss(); 609 | } 610 | 611 | /** 612 | * Gets the width of the HTML content. 613 | * 614 | * @return the width of the HTML content 615 | * @hide 616 | */ 617 | public int getContentWidth() { 618 | return awContents_.getContentWidthCss(); 619 | } 620 | 621 | /** 622 | * Pauses all layout, parsing, and JavaScript timers for all WebViews. This 623 | * is a global requests, not restricted to just this WebView. This can be 624 | * useful if the application has been paused. 625 | */ 626 | public void pauseTimers() { 627 | awContents_.pauseTimers(); 628 | } 629 | 630 | /** 631 | * Resumes all layout, parsing, and JavaScript timers for all WebViews. 632 | * This will resume dispatching all timers. 633 | */ 634 | public void resumeTimers() { 635 | awContents_.resumeTimers(); 636 | } 637 | 638 | /** 639 | * Pauses any extra processing associated with this WebView and its 640 | * associated DOM, plugins, JavaScript etc. For example, if this WebView is 641 | * taken offscreen, this could be called to reduce unnecessary CPU or 642 | * network traffic. When this WebView is again "active", call onResume(). 643 | * Note that this differs from pauseTimers(), which affects all WebViews. 644 | */ 645 | public void onPause() { 646 | awContents_.onPause(); 647 | } 648 | 649 | /** 650 | * Resumes a WebView after a previous call to onPause(). 651 | */ 652 | public void onResume() { 653 | awContents_.onResume(); 654 | } 655 | 656 | /** 657 | * Gets whether this WebView is paused, meaning onPause() was called. 658 | * Calling onResume() sets the paused state back to false. 659 | * 660 | * @hide 661 | */ 662 | public boolean isPaused() { 663 | return awContents_.isPaused(); 664 | } 665 | 666 | /** 667 | * Clears the resource cache. Note that the cache is per-application, so 668 | * this will clear the cache for all WebViews used. 669 | * 670 | * @param includeDiskFiles if false, only the RAM cache is cleared 671 | */ 672 | public void clearCache(boolean includeDiskFiles) { 673 | awContents_.clearCache(includeDiskFiles); 674 | } 675 | 676 | /** 677 | * Tells this WebView to clear its internal back/forward list. 678 | */ 679 | public void clearHistory() { 680 | awContents_.clearHistory(); 681 | } 682 | 683 | /** 684 | * Clears the SSL preferences table stored in response to proceeding with 685 | * SSL certificate errors. 686 | */ 687 | public void clearSslPreferences() { 688 | awContents_.clearSslPreferences(); 689 | } 690 | 691 | /** 692 | * Highlights and scrolls to the next match found by 693 | * {@link #findAllAsync}, wrapping around page boundaries as necessary. 694 | * Notifies any registered {@link FindListener}. If {@link #findAllAsync(String)} 695 | * has not been called yet, or if {@link #clearMatches} has been called since the 696 | * last find operation, this function does nothing. 697 | * 698 | * @param forward the direction to search 699 | * @see #setFindListener 700 | */ 701 | public void findNext(boolean forward) { 702 | awContents_.findNext(forward); 703 | } 704 | 705 | /** 706 | * Finds all instances of find on the page and highlights them, 707 | * asynchronously. Notifies any registered {@link FindListener}. 708 | * Successive calls to this will cancel any pending searches. 709 | * 710 | * @param find the string to find. 711 | * @see #setFindListener 712 | */ 713 | public void findAllAsync(String find) { 714 | awContents_.findAllAsync(find); 715 | } 716 | 717 | /** 718 | * Starts an ActionMode for finding text in this WebView. Only works if this 719 | * WebView is attached to the view system. 720 | * 721 | * @param text if non-null, will be the initial text to search for. 722 | * Otherwise, the last String searched for in this WebView will 723 | * be used to start. 724 | * @param showIme if true, show the IME, assuming the user will begin typing. 725 | * If false and text is non-null, perform a find all. 726 | * @return true if the find dialog is shown, false otherwise 727 | */ 728 | public boolean showFindDialog(String text, boolean showIme) { 729 | // TODO(pwnall): seems useful 730 | return false; 731 | } 732 | 733 | /** 734 | * Clears the highlighting surrounding text matches created by 735 | * {@link #findAllAsync}. 736 | */ 737 | public void clearMatches() { 738 | awContents_.clearMatches(); 739 | } 740 | 741 | /** 742 | * Queries the document to see if it contains any image references. The 743 | * message object will be dispatched with arg1 being set to 1 if images 744 | * were found and 0 if the document does not reference any images. 745 | * 746 | * @param response the message that will be dispatched with the result 747 | */ 748 | public void documentHasImages(Message response) { 749 | awContents_.documentHasImages(response); 750 | } 751 | 752 | /** 753 | * Injects the supplied Java object into this WebView. The object is 754 | * injected into the JavaScript context of the main frame, using the 755 | * supplied name. This allows the Java object's methods to be 756 | * accessed from JavaScript. Only public methods that are annotated with 757 | * {@link us.costan.chrome.ChromeJavascriptInterface} can be accessed from 758 | * JavaScript. 759 | *

Note that injected objects will not 760 | * appear in JavaScript until the page is next (re)loaded. For example: 761 | *

 762 |    * class JsObject {
 763 |    *    {@literal @}ChromeJavascriptInterface
 764 |    *    public String toString() { return "injectedObject"; }
 765 |    * }
 766 |    * webView.addJavascriptInterface(new JsObject(), "injectedObject");
 767 |    * webView.loadData("", "text/html", null);
 768 |    * webView.loadUrl("javascript:alert(injectedObject.toString())");
769 | *

770 | * IMPORTANT: 771 | *

783 | * 784 | * @param object the Java object to inject into this WebView's JavaScript 785 | * context. Null values are ignored. 786 | * @param name the name used to expose the object in JavaScript 787 | */ 788 | public void addJavascriptInterface(Object object, String name) { 789 | awContents_.addPossiblyUnsafeJavascriptInterface(object, name, 790 | ChromeJavascriptInterface.class); 791 | } 792 | 793 | /** 794 | * Removes a previously injected Java object from this WebView. Note that 795 | * the removal will not be reflected in JavaScript until the page is next 796 | * (re)loaded. See {@link #addJavascriptInterface}. 797 | * 798 | * @param name the name used to expose the object in JavaScript 799 | */ 800 | public void removeJavascriptInterface(String name) { 801 | awContents_.removeJavascriptInterface(name); 802 | } 803 | 804 | /** 805 | * Gets the ChromeSettings object used to control the settings for this 806 | * ChromeView. 807 | * 808 | * @return a ChromeSettings object that can be used to control this 809 | * ChromeView's settings 810 | */ 811 | public ChromeSettings getSettings() { 812 | return new ChromeSettingsProxy(awContents_); 813 | } 814 | 815 | public void flingScroll(int vx, int vy) { 816 | awContents_.flingScroll(vx, vy); 817 | } 818 | 819 | /** 820 | * Performs zoom in in this WebView. 821 | * 822 | * @return true if zoom in succeeds, false if no zoom changes 823 | */ 824 | public boolean zoomIn() { 825 | return awContents_.zoomIn(); 826 | } 827 | 828 | /** 829 | * Performs zoom out in this WebView. 830 | * 831 | * @return true if zoom out succeeds, false if no zoom changes 832 | */ 833 | public boolean zoomOut() { 834 | return awContents_.zoomOut(); 835 | } 836 | 837 | 838 | //// Methods outside WebView. 839 | 840 | /** 841 | * Sets up the Chromium libraries backing ChromeView. 842 | * 843 | * This should be called from {@link android.app.Application#onCreate()}. 844 | * 845 | * @param context Android context for the application using ChromeView 846 | */ 847 | public static void initialize(Context context) { 848 | ChromeInitializer.initialize(context); 849 | } 850 | 851 | /** 852 | * The object that implements the WebView API. 853 | */ 854 | public ContentViewCore getContentViewCore() { 855 | return contentViewCore_; 856 | } 857 | 858 | //// Forward a bunch of calls to the Chromium view. 859 | //// Lifted from chromium/src/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView 860 | 861 | public void destroy() { 862 | awContents_.destroy(); 863 | } 864 | 865 | @SuppressLint("WrongCall") 866 | @Override 867 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 868 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 869 | if (awContents_ != null) { 870 | awContents_.onMeasure(widthMeasureSpec, heightMeasureSpec); 871 | } else { 872 | } 873 | } 874 | @Override 875 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 876 | super.onSizeChanged(w, h, oldw, oldh); 877 | if (awContents_ != null) { 878 | awContents_.onSizeChanged(w, h, oldw, oldh); 879 | } 880 | } 881 | @Override 882 | protected void onAttachedToWindow() { 883 | super.onAttachedToWindow(); 884 | if (awContents_ != null) { 885 | awContents_.onAttachedToWindow(); 886 | } 887 | } 888 | @Override 889 | protected void onConfigurationChanged(Configuration newConfig) { 890 | if (awContents_ != null) { 891 | awContents_.onConfigurationChanged(newConfig); 892 | } else { 893 | super.onConfigurationChanged(newConfig); 894 | } 895 | } 896 | @Override 897 | protected void onDetachedFromWindow() { 898 | super.onDetachedFromWindow(); 899 | if (awContents_ != null) { 900 | awContents_.onDetachedFromWindow(); 901 | } 902 | } 903 | @SuppressLint("WrongCall") 904 | @Override 905 | protected void onDraw(Canvas canvas) { 906 | super.onDraw(canvas); 907 | if (awContents_ != null) { 908 | awContents_.onDraw(canvas); 909 | } 910 | } 911 | @Override 912 | protected void onFocusChanged(boolean gainFocus, int direction, 913 | Rect previouslyFocusedRect) { 914 | super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 915 | if (awContents_ != null) { 916 | awContents_.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 917 | } 918 | } 919 | @Override 920 | public boolean onTouchEvent(MotionEvent event) { 921 | if (awContents_ != null) { 922 | return awContents_.onTouchEvent(event); 923 | } else { 924 | return super.onTouchEvent(event); 925 | } 926 | } 927 | @Override 928 | protected void onVisibilityChanged(View changedView, int visibility) { 929 | super.onVisibilityChanged(changedView, visibility); 930 | if (awContents_ != null) { 931 | awContents_.onVisibilityChanged(changedView, visibility); 932 | } 933 | } 934 | @Override 935 | protected void onWindowVisibilityChanged(int visibility) { 936 | super.onWindowVisibilityChanged(visibility); 937 | if (awContents_ != null) { 938 | awContents_.onWindowVisibilityChanged(visibility); 939 | } 940 | } 941 | 942 | //// Forward a bunch more calls to the Chromium view. 943 | //// Lifted from 944 | //// platform/frameworks/base ./core/java/android/webkit/WebKit.java 945 | 946 | @Override 947 | protected int computeHorizontalScrollRange() { 948 | if (awContents_ != null) { 949 | return awContents_.computeHorizontalScrollRange(); 950 | } else { 951 | return super.computeHorizontalScrollRange(); 952 | } 953 | } 954 | @Override 955 | protected int computeHorizontalScrollOffset() { 956 | if (awContents_ != null) { 957 | return awContents_.computeHorizontalScrollOffset(); 958 | } else { 959 | return super.computeHorizontalScrollOffset(); 960 | } 961 | } 962 | @Override 963 | protected int computeVerticalScrollRange() { 964 | if (awContents_ != null) { 965 | return awContents_.computeVerticalScrollRange(); 966 | } else { 967 | return super.computeVerticalScrollRange(); 968 | } 969 | } 970 | @Override 971 | protected int computeVerticalScrollOffset() { 972 | if (awContents_ != null) { 973 | return awContents_.computeVerticalScrollOffset(); 974 | } else { 975 | return super.computeVerticalScrollOffset(); 976 | } 977 | } 978 | @Override 979 | protected int computeVerticalScrollExtent() { 980 | if (awContents_ != null) { 981 | return awContents_.computeVerticalScrollExtent(); 982 | } else { 983 | return super.computeVerticalScrollExtent(); 984 | } 985 | } 986 | @Override 987 | public boolean onHoverEvent(MotionEvent event) { 988 | if (awContents_ != null) { 989 | return awContents_.onHoverEvent(event); 990 | } else { 991 | return super.onHoverEvent(event); 992 | } 993 | } 994 | @Override 995 | public boolean onGenericMotionEvent(MotionEvent event) { 996 | if (awContents_ != null) { 997 | return awContents_.onGenericMotionEvent(event); 998 | } else { 999 | return super.onGenericMotionEvent(event); 1000 | } 1001 | } 1002 | @Override 1003 | public boolean onKeyUp(int keyCode, KeyEvent event) { 1004 | if (awContents_ != null) { 1005 | return awContents_.onKeyUp(keyCode, event); 1006 | } else { 1007 | return super.onKeyUp(keyCode, event); 1008 | } 1009 | } 1010 | @Override 1011 | public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 1012 | super.onInitializeAccessibilityNodeInfo(info); 1013 | if (awContents_ != null) { 1014 | info.setClassName(ChromeView.class.getName()); 1015 | awContents_.onInitializeAccessibilityNodeInfo(info); 1016 | } 1017 | } 1018 | @Override 1019 | public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 1020 | super.onInitializeAccessibilityEvent(event); 1021 | if (awContents_ != null) { 1022 | event.setClassName(ChromeView.class.getName()); 1023 | awContents_.onInitializeAccessibilityEvent(event); 1024 | } 1025 | } 1026 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 1027 | @Override 1028 | public boolean performAccessibilityAction(int action, Bundle arguments) { 1029 | if (awContents_ != null) { 1030 | // Lifted from content.browser.JellyBeanContentView 1031 | if (contentViewCore_.supportsAccessibilityAction(action)) { 1032 | return awContents_.performAccessibilityAction(action, arguments); 1033 | } 1034 | } 1035 | return super.performAccessibilityAction(action, arguments); 1036 | } 1037 | @Override 1038 | public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 1039 | if (awContents_ != null) { 1040 | return awContents_.onCreateInputConnection(outAttrs); 1041 | } else { 1042 | return super.onCreateInputConnection(outAttrs); 1043 | } 1044 | } 1045 | @Override 1046 | public void onWindowFocusChanged(boolean hasWindowFocus) { 1047 | if (awContents_ != null) { 1048 | awContents_.onWindowFocusChanged(hasWindowFocus); 1049 | } 1050 | super.onWindowFocusChanged(hasWindowFocus); 1051 | } 1052 | @Override 1053 | public boolean dispatchKeyEvent(KeyEvent event) { 1054 | if (awContents_ != null) { 1055 | return awContents_.dispatchKeyEvent(event); 1056 | } else { 1057 | return super.dispatchKeyEvent(event); 1058 | } 1059 | } 1060 | @Override 1061 | public boolean dispatchKeyEventPreIme(KeyEvent event) { 1062 | if (awContents_ != null) { 1063 | return contentViewCore_.dispatchKeyEventPreIme(event); 1064 | } else { 1065 | return super.dispatchKeyEventPreIme(event); 1066 | } 1067 | } 1068 | 1069 | //// Forward calls that ContentViewCore responds to. 1070 | 1071 | @Override 1072 | public boolean onCheckIsTextEditor() { 1073 | if (awContents_ != null) { 1074 | return contentViewCore_.onCheckIsTextEditor(); 1075 | } else { 1076 | return super.onCheckIsTextEditor(); 1077 | } 1078 | } 1079 | @Override 1080 | public void scrollTo(int x, int y) { 1081 | super.scrollTo(x, y); 1082 | if (awContents_ != null) { 1083 | contentViewCore_.scrollTo(x, y); 1084 | } 1085 | } 1086 | @Override 1087 | public void scrollBy(int x, int y) { 1088 | super.scrollBy(x, y); 1089 | if (awContents_ != null) { 1090 | contentViewCore_.scrollBy(x, y); 1091 | } 1092 | } 1093 | @Override 1094 | protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 1095 | if (awContents_ != null) { 1096 | return contentViewCore_.awakenScrollBars(startDelay, invalidate); 1097 | } else { 1098 | return super.awakenScrollBars(startDelay, invalidate); 1099 | } 1100 | } 1101 | 1102 | /** Glue that passes calls from the Chromium view to its container (us). */ 1103 | private class ChromeInternalAcccessAdapter implements AwContents.InternalAccessDelegate { 1104 | //// Lifted from chromium/src/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView 1105 | @Override 1106 | public boolean drawChild(Canvas canvas, View child, long drawingTime) { 1107 | return ChromeView.this.drawChild(canvas, child, drawingTime); 1108 | } 1109 | @Override 1110 | public boolean super_onKeyUp(int keyCode, KeyEvent event) { 1111 | return ChromeView.super.onKeyUp(keyCode, event); 1112 | } 1113 | @Override 1114 | public boolean super_dispatchKeyEventPreIme(KeyEvent event) { 1115 | return ChromeView.super.dispatchKeyEventPreIme(event); 1116 | } 1117 | @Override 1118 | public boolean super_dispatchKeyEvent(KeyEvent event) { 1119 | return ChromeView.super.dispatchKeyEvent(event); 1120 | } 1121 | @Override 1122 | public boolean super_onGenericMotionEvent(MotionEvent event) { 1123 | return ChromeView.super.onGenericMotionEvent(event); 1124 | } 1125 | @Override 1126 | public void super_onConfigurationChanged(Configuration newConfig) { 1127 | ChromeView.super.onConfigurationChanged(newConfig); 1128 | } 1129 | @Override 1130 | public void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix) { 1131 | ChromeView.this.onScrollChanged(lPix, tPix, oldlPix, oldtPix); 1132 | } 1133 | @Override 1134 | public boolean awakenScrollBars() { 1135 | return ChromeView.this.awakenScrollBars(); 1136 | } 1137 | @Override 1138 | public boolean super_awakenScrollBars(int startDelay, boolean invalidate) { 1139 | return ChromeView.super.awakenScrollBars(startDelay, invalidate); 1140 | } 1141 | @Override 1142 | public void setMeasuredDimension(int measuredWidth, int measuredHeight) { 1143 | ChromeView.this.setMeasuredDimension(measuredWidth, measuredHeight); 1144 | } 1145 | @Override 1146 | public boolean requestDrawGL(Canvas canvas) { 1147 | if (canvas != null) { 1148 | if (canvas.isHardwareAccelerated()) { 1149 | // TODO(pwnall): figure out what AwContents wants from us, and do it; 1150 | // most likely something to do with 1151 | // AwContents.getAwDrawGLFunction() 1152 | return false; 1153 | } else { 1154 | return false; 1155 | } 1156 | } else { 1157 | if (ChromeView.this.isHardwareAccelerated()) { 1158 | // TODO(pwnall): figure out what AwContents wants from us, and do it; 1159 | // most likely something to do with 1160 | // AwContents.getAwDrawGLFunction() 1161 | return false; 1162 | } else { 1163 | return false; 1164 | } 1165 | } 1166 | } 1167 | @Override 1168 | public void overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, 1169 | int scrollRangeX, int scrollRangeY, int maxOverScrollX, 1170 | int maxOverScrollY, boolean isTouchEvent) { 1171 | ChromeView.this.overScrollBy(deltaX, deltaY, scrollX, scrollY, 1172 | scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, 1173 | isTouchEvent); 1174 | } 1175 | @Override 1176 | public void super_scrollTo(int scrollX, int scrollY) { 1177 | ChromeView.super.scrollTo(scrollX, scrollY); 1178 | } 1179 | @Override 1180 | public int super_getScrollBarStyle() { 1181 | return ChromeView.super.getScrollBarStyle(); 1182 | } 1183 | } 1184 | } 1185 | -------------------------------------------------------------------------------- /src/us/costan/chrome/ChromeViewClient.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome; 2 | 3 | import android.graphics.Bitmap; 4 | import android.net.http.SslError; 5 | import android.os.Message; 6 | import android.view.KeyEvent; 7 | import android.webkit.WebResourceResponse; 8 | 9 | /** 10 | * ChromeView equivalent of WebViewClient. 11 | * 12 | * @see android.webkit.WebViewClient 13 | */ 14 | public class ChromeViewClient { 15 | // Mostly mirrors 16 | // platform/frameworks/base/ ./core/java/android/webkit/WebViewClient 17 | 18 | /** 19 | * Give the host application a chance to take over the control when a new 20 | * url is about to be loaded in the current ChromeView. If ChromeViewClient is not 21 | * provided, by default ChromeView will ask Activity Manager to choose the 22 | * proper handler for the url. If ChromeViewClient is provided, return true 23 | * means the host application handles the url, while return false means the 24 | * current ChromeView handles the url. 25 | * 26 | * @param view The ChromeView that is initiating the callback. 27 | * @param url The url to be loaded. 28 | * @return True if the host application wants to leave the current ChromeView 29 | * and handle the url itself, otherwise return false. 30 | */ 31 | public boolean shouldOverrideUrlLoading(ChromeView view, String url) { 32 | return false; 33 | } 34 | 35 | /** 36 | * Notify the host application that a page has started loading. This method 37 | * is called once for each main frame load so a page with iframes or 38 | * framesets will call onPageStarted one time for the main frame. This also 39 | * means that onPageStarted will not be called when the contents of an 40 | * embedded frame changes, i.e. clicking a link whose target is an iframe. 41 | * 42 | * @param view The ChromeView that is initiating the callback. 43 | * @param url The url to be loaded. 44 | * @param favicon The favicon for this page if it already exists in the 45 | * database. 46 | */ 47 | public void onPageStarted(ChromeView view, String url, Bitmap favicon) { 48 | } 49 | 50 | /** 51 | * Notify the host application that a page has finished loading. This method 52 | * is called only for main frame. When onPageFinished() is called, the 53 | * rendering picture may not be updated yet. To get the notification for the 54 | * new Picture, use {@link ChromeView.PictureListener#onNewPicture}. 55 | * 56 | * @param view The ChromeView that is initiating the callback. 57 | * @param url The url of the page. 58 | */ 59 | public void onPageFinished(ChromeView view, String url) { 60 | } 61 | 62 | /** 63 | * Notify the host application that the ChromeView will load the resource 64 | * specified by the given url. 65 | * 66 | * @param view The ChromeView that is initiating the callback. 67 | * @param url The url of the resource the ChromeView will load. 68 | */ 69 | public void onLoadResource(ChromeView view, String url) { 70 | } 71 | 72 | /** 73 | * Notify the host application of a resource request and allow the 74 | * application to return the data. If the return value is null, the ChromeView 75 | * will continue to load the resource as usual. Otherwise, the return 76 | * response and data will be used. NOTE: This method is called by the 77 | * network thread so clients should exercise caution when accessing private 78 | * data. 79 | * 80 | * @param view The {@link us.costan.chrome.ChromeView} that is requesting the 81 | * resource. 82 | * @param url The raw url of the resource. 83 | * @return A {@link android.webkit.WebResourceResponse} containing the 84 | * response information or null if the ChromeView should load the 85 | * resource itself. 86 | */ 87 | public WebResourceResponse shouldInterceptRequest(ChromeView view, 88 | String url) { 89 | return null; 90 | } 91 | 92 | // These ints must match up to the hidden values in EventHandler. 93 | /** Generic error */ 94 | public static final int ERROR_UNKNOWN = -1; 95 | /** Server or proxy hostname lookup failed */ 96 | public static final int ERROR_HOST_LOOKUP = -2; 97 | /** Unsupported authentication scheme (not basic or digest) */ 98 | public static final int ERROR_UNSUPPORTED_AUTH_SCHEME = -3; 99 | /** User authentication failed on server */ 100 | public static final int ERROR_AUTHENTICATION = -4; 101 | /** User authentication failed on proxy */ 102 | public static final int ERROR_PROXY_AUTHENTICATION = -5; 103 | /** Failed to connect to the server */ 104 | public static final int ERROR_CONNECT = -6; 105 | /** Failed to read or write to the server */ 106 | public static final int ERROR_IO = -7; 107 | /** Connection timed out */ 108 | public static final int ERROR_TIMEOUT = -8; 109 | /** Too many redirects */ 110 | public static final int ERROR_REDIRECT_LOOP = -9; 111 | /** Unsupported URI scheme */ 112 | public static final int ERROR_UNSUPPORTED_SCHEME = -10; 113 | /** Failed to perform SSL handshake */ 114 | public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; 115 | /** Malformed URL */ 116 | public static final int ERROR_BAD_URL = -12; 117 | /** Generic file error */ 118 | public static final int ERROR_FILE = -13; 119 | /** File not found */ 120 | public static final int ERROR_FILE_NOT_FOUND = -14; 121 | /** Too many requests during this load */ 122 | public static final int ERROR_TOO_MANY_REQUESTS = -15; 123 | 124 | /** 125 | * Report an error to the host application. These errors are unrecoverable 126 | * (i.e. the main resource is unavailable). The errorCode parameter 127 | * corresponds to one of the ERROR_* constants. 128 | * @param view The ChromeView that is initiating the callback. 129 | * @param errorCode The error code corresponding to an ERROR_* value. 130 | * @param description A String describing the error. 131 | * @param failingUrl The url that failed to load. 132 | */ 133 | public void onReceivedError(ChromeView view, int errorCode, 134 | String description, String failingUrl) { 135 | } 136 | 137 | /** 138 | * As the host application if the browser should resend data as the 139 | * requested page was a result of a POST. The default is to not resend the 140 | * data. 141 | * 142 | * @param view The ChromeView that is initiating the callback. 143 | * @param dontResend The message to send if the browser should not resend 144 | * @param resend The message to send if the browser should resend data 145 | */ 146 | public void onFormResubmission(ChromeView view, Message dontResend, 147 | Message resend) { 148 | dontResend.sendToTarget(); 149 | } 150 | 151 | /** 152 | * Notify the host application to update its visited links database. 153 | * 154 | * @param view The ChromeView that is initiating the callback. 155 | * @param url The url being visited. 156 | * @param isReload True if this url is being reloaded. 157 | */ 158 | public void doUpdateVisitedHistory(ChromeView view, String url, 159 | boolean isReload) { 160 | } 161 | 162 | /** 163 | * Notify the host application that an SSL error occurred while loading a 164 | * resource. The host application must call either handler.cancel() or 165 | * handler.proceed(). Note that the decision may be retained for use in 166 | * response to future SSL errors. The default behavior is to cancel the 167 | * load. 168 | * 169 | * @param view The ChromeView that is initiating the callback. 170 | * @param handler A ChromeSslErrorHandler object that will handle the user's 171 | * response. 172 | * @param error The SSL error object. 173 | */ 174 | public void onReceivedSslError(ChromeView view, ChromeSslErrorHandler handler, 175 | SslError error) { 176 | handler.cancel(); 177 | } 178 | 179 | /** 180 | * Notify the host application that an SSL error occurred while loading a 181 | * resource, but the ChromeView chose to proceed anyway based on a 182 | * decision retained from a previous response to onReceivedSslError(). 183 | * @hide 184 | */ 185 | public void onProceededAfterSslError(ChromeView view, SslError error) { 186 | } 187 | 188 | /** 189 | * Notify the host application to handle an authentication request. The 190 | * default behavior is to cancel the request. 191 | * 192 | * @param view The ChromeView that is initiating the callback. 193 | * @param handler The HttpAuthHandler that will handle the user's response. 194 | * @param host The host requiring authentication. 195 | * @param realm A description to help store user credentials for future 196 | * visits. 197 | */ 198 | public void onReceivedHttpAuthRequest(ChromeView view, 199 | ChromeHttpAuthHandler handler, String host, String realm) { 200 | handler.cancel(); 201 | } 202 | 203 | /** 204 | * Give the host application a chance to handle the key event synchronously. 205 | * e.g. menu shortcut key events need to be filtered this way. If return 206 | * true, ChromeView will not handle the key event. If return false, ChromeView 207 | * will always handle the key event, so none of the super in the view chain 208 | * will see the key event. The default behavior returns false. 209 | * 210 | * @param view The ChromeView that is initiating the callback. 211 | * @param event The key event. 212 | * @return True if the host application wants to handle the key event 213 | * itself, otherwise return false 214 | */ 215 | public boolean shouldOverrideKeyEvent(ChromeView view, KeyEvent event) { 216 | return false; 217 | } 218 | 219 | /** 220 | * Notify the host application that a key was not handled by the ChromeView. 221 | * Except system keys, ChromeView always consumes the keys in the normal flow 222 | * or if shouldOverrideKeyEvent returns true. This is called asynchronously 223 | * from where the key is dispatched. It gives the host application a chance 224 | * to handle the unhandled key events. 225 | * 226 | * @param view The ChromeView that is initiating the callback. 227 | * @param event The key event. 228 | */ 229 | public void onUnhandledKeyEvent(ChromeView view, KeyEvent event) { 230 | } 231 | 232 | /** 233 | * Notify the host application that the scale applied to the ChromeView has 234 | * changed. 235 | * 236 | * @param view he ChromeView that is initiating the callback. 237 | * @param oldScale The old scale factor 238 | * @param newScale The new scale factor 239 | */ 240 | public void onScaleChanged(ChromeView view, float oldScale, float newScale) { 241 | } 242 | 243 | /** 244 | * Notify the host application that a request to automatically log in the 245 | * user has been processed. 246 | * @param view The ChromeView requesting the login. 247 | * @param realm The account realm used to look up accounts. 248 | * @param account An optional account. If not null, the account should be 249 | * checked against accounts on the device. If it is a valid 250 | * account, it should be used to log in the user. 251 | * @param args Authenticator specific arguments used to log in the user. 252 | */ 253 | public void onReceivedLoginRequest(ChromeView view, String realm, 254 | String account, String args) { 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/us/costan/chrome/ChromeWebClient.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome; 2 | 3 | import android.graphics.Bitmap; 4 | import android.net.Uri; 5 | import android.os.Message; 6 | import android.view.View; 7 | import android.webkit.ConsoleMessage; 8 | import android.webkit.GeolocationPermissions; 9 | import android.webkit.JsPromptResult; 10 | import android.webkit.ValueCallback; 11 | import android.webkit.WebChromeClient.CustomViewCallback; 12 | import android.webkit.WebStorage; 13 | 14 | /** 15 | * ChromeView equivalent of WebChromeClient. 16 | * 17 | * @see android.webkit.WebChromeClient 18 | */ 19 | public class ChromeWebClient { 20 | // Mostly mirrors 21 | // platform/frameworks/base/ ./core/java/android/webkit/WebChromeClient 22 | 23 | /** 24 | * Tell the host application the current progress of loading a page. 25 | * @param view The ChromeView that initiated the callback. 26 | * @param newProgress Current page loading progress, represented by 27 | * an integer between 0 and 100. 28 | */ 29 | public void onProgressChanged(ChromeView view, int newProgress) {} 30 | 31 | /** 32 | * Notify the host application of a change in the document title. 33 | * @param view The ChromeView that initiated the callback. 34 | * @param title A String containing the new title of the document. 35 | */ 36 | public void onReceivedTitle(ChromeView view, String title) {} 37 | 38 | /** 39 | * Notify the host application of a new favicon for the current page. 40 | * @param view The ChromeView that initiated the callback. 41 | * @param icon A Bitmap containing the favicon for the current page. 42 | */ 43 | public void onReceivedIcon(ChromeView view, Bitmap icon) {} 44 | 45 | /** 46 | * Notify the host application of the url for an apple-touch-icon. 47 | * @param view The ChromeView that initiated the callback. 48 | * @param url The icon url. 49 | * @param precomposed True if the url is for a precomposed touch icon. 50 | */ 51 | public void onReceivedTouchIconUrl(ChromeView view, String url, 52 | boolean precomposed) {} 53 | 54 | /** 55 | * Notify the host application that the current page would 56 | * like to show a custom View. 57 | * @param view is the View object to be shown. 58 | * @param callback is the callback to be invoked if and when the view 59 | * is dismissed. 60 | */ 61 | public void onShowCustomView(View view, CustomViewCallback callback) {}; 62 | 63 | /** 64 | * Notify the host application that the current page would 65 | * like to show a custom View in a particular orientation. 66 | * @param view is the View object to be shown. 67 | * @param requestedOrientation An orientation constant as used in 68 | * {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}. 69 | * @param callback is the callback to be invoked if and when the view 70 | * is dismissed. 71 | */ 72 | public void onShowCustomView(View view, int requestedOrientation, 73 | CustomViewCallback callback) {}; 74 | 75 | /** 76 | * Notify the host application that the current page would 77 | * like to hide its custom view. 78 | */ 79 | public void onHideCustomView() {} 80 | 81 | /** 82 | * Request the host application to create a new window. If the host 83 | * application chooses to honor this request, it should return true from 84 | * this method, create a new ChromeView to host the window, insert it into the 85 | * View system and send the supplied resultMsg message to its target with 86 | * the new ChromeView as an argument. If the host application chooses not to 87 | * honor the request, it should return false from this method. The default 88 | * implementation of this method does nothing and hence returns false. 89 | * @param view The ChromeView from which the request for a new window 90 | * originated. 91 | * @param isDialog True if the new window should be a dialog, rather than 92 | * a full-size window. 93 | * @param isUserGesture True if the request was initiated by a user gesture, 94 | * such as the user clicking a link. 95 | * @param resultMsg The message to send when once a new ChromeView has been 96 | * created. resultMsg.obj is a 97 | * {@link ChromeView.ChromeViewTransport} object. This should be 98 | * used to transport the new ChromeView, by calling 99 | * {@link ChromeView.ChromeViewTransport#setChromeView(ChromeView) 100 | * ChromeView.ChromeViewTransport.setChromeView(ChromeView)}. 101 | * @return This method should return true if the host application will 102 | * create a new window, in which case resultMsg should be sent to 103 | * its target. Otherwise, this method should return false. Returning 104 | * false from this method but also sending resultMsg will result in 105 | * undefined behavior. 106 | */ 107 | public boolean onCreateWindow(ChromeView view, boolean isDialog, 108 | boolean isUserGesture, Message resultMsg) { 109 | return false; 110 | } 111 | 112 | /** 113 | * Request display and focus for this ChromeView. This may happen due to 114 | * another ChromeView opening a link in this ChromeView and requesting that this 115 | * ChromeView be displayed. 116 | * @param view The ChromeView that needs to be focused. 117 | */ 118 | public void onRequestFocus(ChromeView view) {} 119 | 120 | /** 121 | * Notify the host application to close the given ChromeView and remove it 122 | * from the view system if necessary. At this point, WebCore has stopped 123 | * any loading in this window and has removed any cross-scripting ability 124 | * in javascript. 125 | * @param window The ChromeView that needs to be closed. 126 | */ 127 | public void onCloseWindow(ChromeView window) {} 128 | 129 | /** 130 | * Tell the client to display a javascript alert dialog. If the client 131 | * returns true, ChromeView will assume that the client will handle the 132 | * dialog. If the client returns false, it will continue execution. 133 | * @param view The ChromeView that initiated the callback. 134 | * @param url The url of the page requesting the dialog. 135 | * @param message Message to be displayed in the window. 136 | * @param result A JsResult to confirm that the user hit enter. 137 | * @return boolean Whether the client will handle the alert dialog. 138 | */ 139 | public boolean onJsAlert(ChromeView view, String url, String message, 140 | ChromeJsResult result) { 141 | return false; 142 | } 143 | 144 | /** 145 | * Tell the client to display a confirm dialog to the user. If the client 146 | * returns true, ChromeView will assume that the client will handle the 147 | * confirm dialog and call the appropriate JsResult method. If the 148 | * client returns false, a default value of false will be returned to 149 | * javascript. The default behavior is to return false. 150 | * @param view The ChromeView that initiated the callback. 151 | * @param url The url of the page requesting the dialog. 152 | * @param message Message to be displayed in the window. 153 | * @param result A JsResult used to send the user's response to 154 | * javascript. 155 | * @return boolean Whether the client will handle the confirm dialog. 156 | */ 157 | public boolean onJsConfirm(ChromeView view, String url, String message, 158 | ChromeJsResult result) { 159 | return false; 160 | } 161 | 162 | /** 163 | * Tell the client to display a prompt dialog to the user. If the client 164 | * returns true, ChromeView will assume that the client will handle the 165 | * prompt dialog and call the appropriate JsPromptResult method. If the 166 | * client returns false, a default value of false will be returned to to 167 | * javascript. The default behavior is to return false. 168 | * @param view The ChromeView that initiated the callback. 169 | * @param url The url of the page requesting the dialog. 170 | * @param message Message to be displayed in the window. 171 | * @param defaultValue The default value displayed in the prompt dialog. 172 | * @param result A JsPromptResult used to send the user's reponse to 173 | * javascript. 174 | * @return boolean Whether the client will handle the prompt dialog. 175 | */ 176 | public boolean onJsPrompt(ChromeView view, String url, String message, 177 | String defaultValue, JsPromptResult result) { 178 | return false; 179 | } 180 | 181 | /** 182 | * Tell the client to display a dialog to confirm navigation away from the 183 | * current page. This is the result of the onbeforeunload javascript event. 184 | * If the client returns true, ChromeView will assume that the client will 185 | * handle the confirm dialog and call the appropriate JsResult method. If 186 | * the client returns false, a default value of true will be returned to 187 | * javascript to accept navigation away from the current page. The default 188 | * behavior is to return false. Setting the JsResult to true will navigate 189 | * away from the current page, false will cancel the navigation. 190 | * @param view The ChromeView that initiated the callback. 191 | * @param url The url of the page requesting the dialog. 192 | * @param message Message to be displayed in the window. 193 | * @param result A JsResult used to send the user's response to 194 | * javascript. 195 | * @return boolean Whether the client will handle the confirm dialog. 196 | */ 197 | public boolean onJsBeforeUnload(ChromeView view, String url, String message, 198 | ChromeJsResult result) { 199 | return false; 200 | } 201 | 202 | /** 203 | * Tell the client that the quota has been exceeded for the Web SQL Database 204 | * API for a particular origin and request a new quota. The client must 205 | * respond by invoking the 206 | * {@link WebStorage.QuotaUpdater#updateQuota(long) updateQuota(long)} 207 | * method of the supplied {@link WebStorage.QuotaUpdater} instance. The 208 | * minimum value that can be set for the new quota is the current quota. The 209 | * default implementation responds with the current quota, so the quota will 210 | * not be increased. 211 | * @param url The URL of the page that triggered the notification 212 | * @param databaseIdentifier The identifier of the database where the quota 213 | * was exceeded. 214 | * @param quota The quota for the origin, in bytes 215 | * @param estimatedDatabaseSize The estimated size of the offending 216 | * database, in bytes 217 | * @param totalQuota The total quota for all origins, in bytes 218 | * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which 219 | * must be used to inform the ChromeView of the new quota. 220 | */ 221 | // Note that the callback must always be executed at some point to ensure 222 | // that the sleeping WebCore thread is woken up. 223 | public void onExceededDatabaseQuota(String url, String databaseIdentifier, 224 | long quota, long estimatedDatabaseSize, long totalQuota, 225 | WebStorage.QuotaUpdater quotaUpdater) { 226 | // This default implementation passes the current quota back to WebCore. 227 | // WebCore will interpret this that new quota was declined. 228 | quotaUpdater.updateQuota(quota); 229 | } 230 | 231 | /** 232 | * Tell the client that the quota has been reached for the Application Cache 233 | * API and request a new quota. The client must respond by invoking the 234 | * {@link WebStorage.QuotaUpdater#updateQuota(long) updateQuota(long)} 235 | * method of the supplied {@link WebStorage.QuotaUpdater} instance. The 236 | * minimum value that can be set for the new quota is the current quota. The 237 | * default implementation responds with the current quota, so the quota will 238 | * not be increased. 239 | * @param requiredStorage The amount of storage required by the Application 240 | * Cache operation that triggered this notification, 241 | * in bytes. 242 | * @param quota The quota, in bytes 243 | * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which 244 | * must be used to inform the ChromeView of the new quota. 245 | */ 246 | // Note that the callback must always be executed at some point to ensure 247 | // that the sleeping WebCore thread is woken up. 248 | public void onReachedMaxAppCacheSize(long requiredStorage, long quota, 249 | WebStorage.QuotaUpdater quotaUpdater) { 250 | quotaUpdater.updateQuota(quota); 251 | } 252 | 253 | /** 254 | * Notify the host application that web content from the specified origin 255 | * is attempting to use the Geolocation API, but no permission state is 256 | * currently set for that origin. The host application should invoke the 257 | * specified callback with the desired permission state. See 258 | * {@link GeolocationPermissions} for details. 259 | * @param origin The origin of the web content attempting to use the 260 | * Geolocation API. 261 | * @param callback The callback to use to set the permission state for the 262 | * origin. 263 | */ 264 | public void onGeolocationPermissionsShowPrompt(String origin, 265 | GeolocationPermissions.Callback callback) {} 266 | 267 | /** 268 | * Notify the host application that a request for Geolocation permissions, 269 | * made with a previous call to 270 | * {@link #onGeolocationPermissionsShowPrompt(String,GeolocationPermissions.Callback) onGeolocationPermissionsShowPrompt()} 271 | * has been canceled. Any related UI should therefore be hidden. 272 | */ 273 | public void onGeolocationPermissionsHidePrompt() {} 274 | 275 | /** 276 | * Tell the client that a JavaScript execution timeout has occured. And the 277 | * client may decide whether or not to interrupt the execution. If the 278 | * client returns true, the JavaScript will be interrupted. If the client 279 | * returns false, the execution will continue. Note that in the case of 280 | * continuing execution, the timeout counter will be reset, and the callback 281 | * will continue to occur if the script does not finish at the next check 282 | * point. 283 | * @return boolean Whether the JavaScript execution should be interrupted. 284 | */ 285 | public boolean onJsTimeout() { 286 | return true; 287 | } 288 | 289 | /** 290 | * Report a JavaScript error message to the host application. The ChromeClient 291 | * should override this to process the log message as they see fit. 292 | * @param message The error message to report. 293 | * @param lineNumber The line number of the error. 294 | * @param sourceID The name of the source file that caused the error. 295 | * @deprecated Use {@link #onConsoleMessage(ConsoleMessage) onConsoleMessage(ConsoleMessage)} 296 | * instead. 297 | */ 298 | @Deprecated 299 | public void onConsoleMessage(String message, int lineNumber, String sourceID) { } 300 | 301 | /** 302 | * Report a JavaScript console message to the host application. The ChromeClient 303 | * should override this to process the log message as they see fit. 304 | * @param consoleMessage Object containing details of the console message. 305 | * @return true if the message is handled by the client. 306 | */ 307 | public boolean onConsoleMessage(ConsoleMessage consoleMessage) { 308 | // Call the old version of this function for backwards compatability. 309 | onConsoleMessage(consoleMessage.message(), consoleMessage.lineNumber(), 310 | consoleMessage.sourceId()); 311 | return false; 312 | } 313 | 314 | /** 315 | * When not playing, video elements are represented by a 'poster' image. The 316 | * image to use can be specified by the poster attribute of the video tag in 317 | * HTML. If the attribute is absent, then a default poster will be used. This 318 | * method allows the ChromeClient to provide that default image. 319 | * 320 | * @return Bitmap The image to use as a default poster, or null if no such image is 321 | * available. 322 | */ 323 | public Bitmap getDefaultVideoPoster() { 324 | return null; 325 | } 326 | 327 | /** 328 | * When the user starts to playback a video element, it may take time for enough 329 | * data to be buffered before the first frames can be rendered. While this buffering 330 | * is taking place, the ChromeClient can use this function to provide a View to be 331 | * displayed. For example, the ChromeClient could show a spinner animation. 332 | * 333 | * @return View The View to be displayed whilst the video is loading. 334 | */ 335 | public View getVideoLoadingProgressView() { 336 | return null; 337 | } 338 | 339 | /** Obtains a list of all visited history items, used for link coloring 340 | */ 341 | public void getVisitedHistory(ValueCallback callback) { 342 | } 343 | 344 | /** 345 | * Tell the client to open a file chooser. 346 | * @param uploadFile A ValueCallback to set the URI of the file to upload. 347 | * onReceiveValue must be called to wake up the thread.a 348 | * @param acceptType The value of the 'accept' attribute of the input tag 349 | * associated with this file picker. 350 | * @param capture The value of the 'capture' attribute of the input tag 351 | * associated with this file picker. 352 | * @hide 353 | */ 354 | public void openFileChooser(ValueCallback uploadFile, String acceptType, String capture) { 355 | uploadFile.onReceiveValue(null); 356 | } 357 | 358 | /** 359 | * Tell the client that the page being viewed is web app capable, 360 | * i.e. has specified the fullscreen-web-app-capable meta tag. 361 | * @hide 362 | */ 363 | public void setInstallableWebApp() { } 364 | 365 | /** 366 | * Tell the client that the page being viewed has an autofillable 367 | * form and the user would like to set a profile up. 368 | * @param msg A Message to send once the user has successfully 369 | * set up a profile and to inform the WebTextView it should 370 | * now autofill using that new profile. 371 | * @hide 372 | */ 373 | public void setupAutoFill(Message msg) { } 374 | } 375 | -------------------------------------------------------------------------------- /src/us/costan/chrome/impl/ChromeAwContentsClientProxy.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome.impl; 2 | 3 | import org.chromium.android_webview.AwContentsClient; 4 | import org.chromium.android_webview.AwHttpAuthHandler; 5 | import org.chromium.android_webview.InterceptedRequestData; 6 | import org.chromium.android_webview.JsPromptResultReceiver; 7 | import org.chromium.android_webview.JsResultReceiver; 8 | 9 | import us.costan.chrome.ChromeJsResult; 10 | import us.costan.chrome.ChromeView; 11 | import us.costan.chrome.ChromeViewClient; 12 | import us.costan.chrome.ChromeWebClient; 13 | import android.annotation.TargetApi; 14 | import android.graphics.Bitmap; 15 | import android.graphics.Picture; 16 | import android.net.http.SslError; 17 | import android.os.Build; 18 | import android.os.Message; 19 | import android.view.KeyEvent; 20 | import android.view.View; 21 | import android.webkit.ConsoleMessage; 22 | import android.webkit.DownloadListener; 23 | import android.webkit.ValueCallback; 24 | import android.webkit.WebResourceResponse; 25 | import android.webkit.GeolocationPermissions.Callback; 26 | import android.webkit.WebChromeClient.CustomViewCallback; 27 | import android.webkit.WebView.FindListener; 28 | 29 | /** Glue that passes calls from the Chromium view to a WebChromeClient. */ 30 | public class ChromeAwContentsClientProxy extends AwContentsClient { 31 | // Inspired from 32 | // chromium/src/android_webview/test/shell/src/org/chromium/android_webview/test/NullContentsClient:w 33 | 34 | // chromium/src/android_webview/javatests/src/org/chromium/android_webview/tests/*ContentsClient 35 | // http://developer.android.com/reference/android/webkit/WebChromeClient.html 36 | 37 | /** The view whose clients are proxied by this instance. */ 38 | private final ChromeView view_; 39 | 40 | /** ChromeView equivalent of WebViewClient. */ 41 | private ChromeViewClient viewClient_; 42 | 43 | /** ChromeView equivalent of WebChromeClient. */ 44 | private ChromeWebClient webClient_; 45 | 46 | /** Receives download notifications. */ 47 | private DownloadListener downloadListener_; 48 | 49 | /** Receives find results notifications. */ 50 | private FindListener findListener_; 51 | 52 | 53 | /** Resets the ChromeViewClient proxy target. */ 54 | public void setChromeViewClient(ChromeViewClient chromeViewClient) { 55 | viewClient_ = chromeViewClient; 56 | } 57 | 58 | /** Resets the ChromeWebClient proxy target. */ 59 | public void setChromeWebClient(ChromeWebClient chromeWebClient) { 60 | webClient_ = chromeWebClient; 61 | } 62 | 63 | /** Resets the DownloadListener proxy target. */ 64 | public void setDownloadListener(DownloadListener downloadListener) { 65 | downloadListener_ = downloadListener; 66 | } 67 | 68 | /** Resets the FindListener proxy target. */ 69 | public void setFindListener(FindListener findListener) { 70 | findListener_ = findListener; 71 | } 72 | 73 | /** 74 | * Creates a new proxy. 75 | * 76 | * @param chromeView The view whose clients are proxied by this instance. 77 | */ 78 | public ChromeAwContentsClientProxy(ChromeView chromeView) { 79 | view_ = chromeView; 80 | viewClient_ = null; 81 | webClient_ = null; 82 | } 83 | 84 | @Override 85 | public void onHideCustomView() { 86 | // TODO Auto-generated method stub 87 | } 88 | 89 | @Override 90 | public Bitmap getDefaultVideoPoster() { 91 | // TODO Auto-generated method stub 92 | return null; 93 | } 94 | 95 | //// WebChromeClient inexact proxies. 96 | @Override 97 | protected void handleJsAlert(String url, String message, 98 | JsResultReceiver receiver) { 99 | if (webClient_ != null) { 100 | ChromeJsResult result = new ChromeJsResult( 101 | new ChromeJsResultReceiverProxy(receiver)); 102 | if (webClient_.onJsAlert(view_, url, message, result)) { 103 | return; // Alert will be handled by the client. 104 | } 105 | } 106 | receiver.cancel(); // Default alert handling. 107 | } 108 | @Override 109 | protected void handleJsBeforeUnload(String url, String message, 110 | JsResultReceiver receiver) { 111 | if (webClient_ != null) { 112 | ChromeJsResult result = new ChromeJsResult( 113 | new ChromeJsResultReceiverProxy(receiver)); 114 | if (webClient_.onJsBeforeUnload(view_, url, message, 115 | result)) { 116 | return; // Alert will be handled by the client. 117 | } 118 | } 119 | receiver.cancel(); // Default alert handling. 120 | } 121 | @Override 122 | protected void handleJsConfirm(String url, String message, 123 | JsResultReceiver receiver) { 124 | if (webClient_ != null) { 125 | ChromeJsResult result = new ChromeJsResult( 126 | new ChromeJsResultReceiverProxy(receiver)); 127 | if (webClient_.onJsAlert(view_, url, message, result)) { 128 | return; // Alert will be handled by the client. 129 | } 130 | } 131 | receiver.cancel(); // Default alert handling. 132 | } 133 | @Override 134 | protected void handleJsPrompt(String url, String message, 135 | String defaultValue, JsPromptResultReceiver receiver) { 136 | if (webClient_ != null) { 137 | ChromeJsResult result = new ChromeJsResult( 138 | new ChromeJsPromptResultProxy(receiver)); 139 | if (webClient_.onJsAlert(view_, url, message, result)) { 140 | return; // Alert will be handled by the client. 141 | } 142 | } 143 | receiver.cancel(); // Default alert handling. 144 | } 145 | 146 | //// WebChromeClient proxy methods. 147 | @Override 148 | public void onProgressChanged(int progress) { 149 | if (webClient_ != null) 150 | webClient_.onProgressChanged(view_, progress); 151 | } 152 | @Override 153 | public void onReceivedIcon(Bitmap bitmap) { 154 | if (webClient_ != null) 155 | webClient_.onReceivedIcon(view_, bitmap); 156 | } 157 | @Override 158 | public void onReceivedTouchIconUrl(String url, boolean precomposed) { 159 | if (webClient_ != null) 160 | webClient_.onReceivedTouchIconUrl(view_, url, precomposed); 161 | } 162 | @Override 163 | public void onShowCustomView(View view, int requestedOrientation, 164 | CustomViewCallback callback) { 165 | if (webClient_ != null) { 166 | webClient_.onShowCustomView(view_, requestedOrientation, 167 | callback); 168 | } 169 | } 170 | @Override 171 | protected boolean onCreateWindow(boolean isDialog, boolean isUserGesture) { 172 | if (webClient_ != null) { 173 | // TODO(pwnall): figure out what to do here 174 | Message resultMsg = new Message(); 175 | resultMsg.setTarget(null); 176 | resultMsg.obj = null; // WebView.WebViewTransport 177 | return webClient_.onCreateWindow(view_, isDialog, 178 | isUserGesture, resultMsg); 179 | } else { 180 | return false; 181 | } 182 | } 183 | @Override 184 | protected void onRequestFocus() { 185 | if (webClient_ != null) 186 | webClient_.onRequestFocus(view_); 187 | } 188 | @Override 189 | protected void onCloseWindow() { 190 | if (webClient_ != null) 191 | webClient_.onCloseWindow(view_); 192 | } 193 | @Override 194 | public void onGeolocationPermissionsShowPrompt(String origin, 195 | Callback callback) { 196 | if (webClient_ != null) { 197 | webClient_.onGeolocationPermissionsShowPrompt(origin, callback); 198 | } else { 199 | callback.invoke(origin, false, false); 200 | } 201 | } 202 | @Override 203 | public void onGeolocationPermissionsHidePrompt() { 204 | if (webClient_ != null) 205 | webClient_.onGeolocationPermissionsHidePrompt(); 206 | } 207 | @Override 208 | public boolean onConsoleMessage(ConsoleMessage consoleMessage) { 209 | if (webClient_ != null) { 210 | return webClient_.onConsoleMessage(consoleMessage); 211 | } else { 212 | return false; 213 | } 214 | } 215 | @Override 216 | protected View getVideoLoadingProgressView() { 217 | if (webClient_ != null) { 218 | return webClient_.getVideoLoadingProgressView(); 219 | } else { 220 | return null; 221 | } 222 | } 223 | @Override 224 | public void getVisitedHistory(ValueCallback callback) { 225 | if (webClient_ != null) { 226 | webClient_.getVisitedHistory(callback); 227 | } else { 228 | callback.onReceiveValue(new String[] {}); 229 | } 230 | } 231 | @Override 232 | public void onReceivedTitle(String title) { 233 | if (viewClient_ != null) { 234 | webClient_.onReceivedTitle(view_, title); 235 | } 236 | } 237 | 238 | //// WebViewClient proxy methods. 239 | @Override 240 | public void onPageStarted(String url) { 241 | if (viewClient_ != null) 242 | viewClient_.onPageStarted(view_, url, null); 243 | } 244 | @Override 245 | public void onPageFinished(String url) { 246 | if (viewClient_ != null) 247 | viewClient_.onPageFinished(view_, url); 248 | } 249 | @Override 250 | public void onLoadResource(String url) { 251 | if (viewClient_ != null) 252 | viewClient_.onLoadResource(view_, url); 253 | } 254 | @Override 255 | public InterceptedRequestData shouldInterceptRequest(String url) { 256 | if (viewClient_ != null) { 257 | WebResourceResponse response = 258 | viewClient_.shouldInterceptRequest(view_, url); 259 | if (response != null) { 260 | return new InterceptedRequestData(response.getMimeType(), 261 | response.getEncoding(), response.getData()); 262 | } 263 | } 264 | return null; 265 | } 266 | @Override 267 | public void onReceivedError(int errorCode, String description, 268 | String failingUrl) { 269 | if (viewClient_ != null) { 270 | viewClient_.onReceivedError(view_, errorCode, description, failingUrl); 271 | } 272 | } 273 | @Override 274 | public void onFormResubmission(Message dontResend, Message resend) { 275 | if (viewClient_ != null) { 276 | viewClient_.onFormResubmission(view_, dontResend, resend); 277 | } else { 278 | dontResend.sendToTarget(); 279 | } 280 | } 281 | @Override 282 | public void doUpdateVisitedHistory(String url, boolean isReload) { 283 | if (viewClient_ != null) 284 | viewClient_.doUpdateVisitedHistory(view_, url, isReload); 285 | } 286 | @Override 287 | public void onReceivedSslError(ValueCallback callback, 288 | SslError error) { 289 | if (viewClient_ != null) { 290 | ChromeSslErrorHandlerProxy handler = 291 | new ChromeSslErrorHandlerProxy(callback); 292 | viewClient_.onReceivedSslError(view_, handler, error); 293 | } else { 294 | callback.onReceiveValue(false); 295 | } 296 | } 297 | @Override 298 | public void onReceivedHttpAuthRequest(AwHttpAuthHandler handler, 299 | String host, String realm) { 300 | if (viewClient_ != null) { 301 | ChromeHttpAuthHandlerProxy httpAuthHandler = 302 | new ChromeHttpAuthHandlerProxy(handler); 303 | viewClient_.onReceivedHttpAuthRequest(view_, httpAuthHandler, 304 | host, realm); 305 | } else { 306 | handler.cancel(); 307 | } 308 | } 309 | @Override 310 | public void onUnhandledKeyEvent(KeyEvent event) { 311 | if (viewClient_ != null) 312 | viewClient_.onUnhandledKeyEvent(view_, event); 313 | } 314 | @Override 315 | public void onScaleChangedScaled(float oldScale, float newScale) { 316 | if (viewClient_ != null) 317 | viewClient_.onScaleChanged(view_, oldScale, newScale); 318 | } 319 | @Override 320 | public void onReceivedLoginRequest(String realm, String account, 321 | String args) { 322 | if (viewClient_ != null) { 323 | viewClient_.onReceivedLoginRequest(view_, realm, account, 324 | args); 325 | } 326 | } 327 | @Override 328 | public boolean shouldOverrideKeyEvent(KeyEvent event) { 329 | if (viewClient_ != null) { 330 | return viewClient_.shouldOverrideKeyEvent(view_, event); 331 | } else { 332 | return false; 333 | } 334 | } 335 | @Override 336 | public boolean shouldOverrideUrlLoading(String url) { 337 | if (viewClient_ != null) { 338 | return viewClient_.shouldOverrideUrlLoading(view_, url); 339 | } else { 340 | return false; 341 | } 342 | } 343 | 344 | // DownloadListener proxy methods. 345 | @Override 346 | public void onDownloadStart(String url, String userAgent, 347 | String contentDisposition, String mimeType, long contentLength) { 348 | if (downloadListener_ != null) { 349 | downloadListener_.onDownloadStart(url, userAgent, contentDisposition, 350 | mimeType, contentLength); 351 | } 352 | } 353 | 354 | // FindListener proxy methods. 355 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 356 | @Override 357 | public void onFindResultReceived(int activeMatchOrdinal, 358 | int numberOfMatches, boolean isDoneCounting) { 359 | if (findListener_ != null) { 360 | findListener_.onFindResultReceived(activeMatchOrdinal, numberOfMatches, 361 | isDoneCounting); 362 | } 363 | } 364 | 365 | // PictureListener is deprecated, so we don't proxy it. 366 | @Override 367 | public void onNewPicture(Picture picture) { 368 | return; 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /src/us/costan/chrome/impl/ChromeHttpAuthHandlerProxy.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome.impl; 2 | 3 | import org.chromium.android_webview.AwHttpAuthHandler; 4 | 5 | import us.costan.chrome.ChromeHttpAuthHandler; 6 | 7 | /** 8 | * Proxies from ChromeHttpAuthHandler to AwHttpAuthHandler. 9 | * 10 | * @hide 11 | */ 12 | public class ChromeHttpAuthHandlerProxy implements ChromeHttpAuthHandler { 13 | /** The proxy target. */ 14 | private AwHttpAuthHandler target_; 15 | 16 | public ChromeHttpAuthHandlerProxy(AwHttpAuthHandler target) { 17 | target_ = target; 18 | } 19 | @Override 20 | public boolean useHttpAuthUsernamePassword() { 21 | return false; 22 | } 23 | @Override 24 | public void cancel() { 25 | target_.cancel(); 26 | } 27 | @Override 28 | public void proceed(String username, String password) { 29 | target_.proceed(username, password); 30 | } 31 | @Override 32 | public boolean suppressDialog() { 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/us/costan/chrome/impl/ChromeInitializer.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome.impl; 2 | 3 | import org.chromium.android_webview.AwBrowserProcess; 4 | import org.chromium.android_webview.AwResource; 5 | import org.chromium.content.browser.ResourceExtractor; 6 | import org.chromium.content.common.CommandLine; 7 | import org.chromium.ui.R; 8 | 9 | import us.costan.chrome.ChromeView; 10 | import android.content.Context; 11 | 12 | /** 13 | * Chromium setup chores. 14 | */ 15 | public class ChromeInitializer { 16 | private static final String[] MANDATORY_PAKS = { "webviewchromium.pak" }; 17 | 18 | /** 19 | * The entry point to the initialization process. 20 | * 21 | * This is called by {@link ChromeView#initialize(Context)}. 22 | * 23 | * @param context Android context for the application using ChromeView 24 | */ 25 | public static void initialize(Context context) { 26 | if (initializeCalled_) { 27 | return; 28 | } 29 | initializeCalled_ = true; 30 | 31 | // Initialization lifted from 32 | // chromium/src/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellResourceProvider 33 | 34 | AwResource.setResources(context.getResources()); 35 | 36 | AwResource.RAW_LOAD_ERROR = R.raw.blank_html; 37 | AwResource.RAW_NO_DOMAIN = R.raw.blank_html; 38 | 39 | AwResource.STRING_DEFAULT_TEXT_ENCODING = R.string.default_encoding; 40 | 41 | // Initialization lifted from 42 | // chromium/src/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication 43 | 44 | CommandLine.initFromFile("/data/local/chrome-command-line"); 45 | 46 | ResourceExtractor.setMandatoryPaksToExtract(MANDATORY_PAKS); 47 | ResourceExtractor.setExtractImplicitLocaleForTesting(false); 48 | AwBrowserProcess.loadLibrary(); 49 | AwBrowserProcess.start(context); 50 | } 51 | 52 | /** Ensures that initialize() is only called once. */ 53 | private static boolean initializeCalled_ = false; 54 | } 55 | -------------------------------------------------------------------------------- /src/us/costan/chrome/impl/ChromeJsPromptResultProxy.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome.impl; 2 | 3 | import org.chromium.android_webview.JsPromptResultReceiver; 4 | 5 | import us.costan.chrome.ChromeJsPromptResult; 6 | import us.costan.chrome.ChromeJsResult; 7 | 8 | /** 9 | * Proxies from android_webkit's JsResultReceiver to JsPromptResult. 10 | * 11 | * @hide 12 | */ 13 | public class ChromeJsPromptResultProxy 14 | implements ChromeJsResult.ResultReceiver { 15 | 16 | /** The proxy target. */ 17 | private JsPromptResultReceiver target_; 18 | 19 | public ChromeJsPromptResultProxy(JsPromptResultReceiver target) { 20 | target_ = target; 21 | } 22 | @Override 23 | public void onJsResultComplete(ChromeJsResult result) { 24 | ChromeJsPromptResult promptResult = (ChromeJsPromptResult)result; 25 | if (result.getResult()) { 26 | target_.confirm(promptResult.getStringResult()); 27 | } else { 28 | target_.cancel(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/us/costan/chrome/impl/ChromeJsResultReceiverProxy.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome.impl; 2 | 3 | import org.chromium.android_webview.JsResultReceiver; 4 | 5 | import us.costan.chrome.ChromeJsResult; 6 | 7 | /** 8 | * Proxies from android_webkit's JsResultReceiver to JsResult. 9 | * 10 | * @hide 11 | */ 12 | public class ChromeJsResultReceiverProxy implements 13 | ChromeJsResult.ResultReceiver { 14 | 15 | /** The proxy target. */ 16 | private JsResultReceiver target_; 17 | 18 | public ChromeJsResultReceiverProxy(JsResultReceiver target) { 19 | target_ = target; 20 | } 21 | @Override 22 | public void onJsResultComplete(ChromeJsResult result) { 23 | if (result.getResult()) { 24 | target_.confirm(); 25 | } else { 26 | target_.cancel(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/us/costan/chrome/impl/ChromeSettingsProxy.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome.impl; 2 | 3 | import org.chromium.android_webview.AwContents; 4 | import org.chromium.android_webview.AwSettings; 5 | import org.chromium.content.browser.ContentSettings; 6 | 7 | import android.annotation.SuppressLint; 8 | import android.webkit.WebSettings.LayoutAlgorithm; 9 | import android.webkit.WebSettings.PluginState; 10 | import android.webkit.WebSettings.RenderPriority; 11 | import android.webkit.WebSettings.ZoomDensity; 12 | import us.costan.chrome.ChromeSettings; 13 | 14 | /** Proxies between ChromeSettings and ContentsSettings / WebSettings. */ 15 | public class ChromeSettingsProxy extends ChromeSettings { 16 | /** The AwContents powering the ChromeView whose settings we're proxying. */ 17 | private AwContents awContents_; 18 | 19 | /** ContentsSettings proxy target. */ 20 | private ContentSettings contents_; 21 | 22 | /** WebSettings proxy target. */ 23 | private AwSettings web_; 24 | 25 | public ChromeSettingsProxy(AwContents awContents) { 26 | awContents_ = awContents; 27 | contents_ = awContents_.getContentSettings(); 28 | web_ = awContents_.getSettings(); 29 | } 30 | 31 | @Override 32 | public void setSupportZoom(boolean support) { 33 | web_.setSupportZoom(support); 34 | } 35 | @Override 36 | public boolean supportZoom() { 37 | return web_.supportZoom(); 38 | } 39 | @Override 40 | public void setMediaPlaybackRequiresUserGesture(boolean require) { 41 | web_.setMediaPlaybackRequiresUserGesture(require); 42 | } 43 | @Override 44 | public boolean getMediaPlaybackRequiresUserGesture() { 45 | return web_.getMediaPlaybackRequiresUserGesture(); 46 | } 47 | @Override 48 | public void setBuiltInZoomControls(boolean enabled) { 49 | web_.setBuiltInZoomControls(enabled); 50 | } 51 | @Override 52 | public boolean getBuiltInZoomControls() { 53 | return web_.getBuiltInZoomControls(); 54 | } 55 | @Override 56 | public void setDisplayZoomControls(boolean enabled) { 57 | web_.setDisplayZoomControls(enabled); 58 | } 59 | @Override 60 | public boolean getDisplayZoomControls() { 61 | return web_.getDisplayZoomControls(); 62 | } 63 | @Override 64 | public void setAllowFileAccess(boolean allow) { 65 | web_.setAllowFileAccess(allow); 66 | } 67 | @Override 68 | public boolean getAllowFileAccess() { 69 | return web_.getAllowFileAccess(); 70 | } 71 | @Override 72 | public void setAllowContentAccess(boolean allow) { 73 | web_.setAllowContentAccess(allow); 74 | } 75 | @Override 76 | public boolean getAllowContentAccess() { 77 | return web_.getAllowContentAccess(); 78 | } 79 | @Override 80 | public void setLoadWithOverviewMode(boolean overview) { 81 | web_.setLoadWithOverviewMode(overview); 82 | } 83 | @Override 84 | public boolean getLoadWithOverviewMode() { 85 | return web_.getLoadWithOverviewMode(); 86 | } 87 | @Override 88 | public void setSaveFormData(boolean save) { 89 | web_.setSaveFormData(save); 90 | } 91 | @Override 92 | public boolean getSaveFormData() { 93 | return web_.getSaveFormData(); 94 | } 95 | @Override 96 | public void setSavePassword(boolean save) { 97 | // TODO Auto-generated method stub 98 | } 99 | @Override 100 | public boolean getSavePassword() { 101 | // TODO Auto-generated method stub 102 | return false; 103 | } 104 | @Override 105 | public void setTextZoom(int textZoom) { 106 | web_.setTextZoom(textZoom); 107 | } 108 | @Override 109 | public int getTextZoom() { 110 | return web_.getTextZoom(); 111 | } 112 | @Override 113 | public void setDefaultZoom(ZoomDensity zoom) { 114 | // TODO Auto-generated method stub 115 | } 116 | @Override 117 | public ZoomDensity getDefaultZoom() { 118 | // TODO Auto-generated method stub 119 | return null; 120 | } 121 | @Override 122 | public void setLightTouchEnabled(boolean enabled) { 123 | // TODO Auto-generated method stub 124 | } 125 | @Override 126 | public boolean getLightTouchEnabled() { 127 | // TODO Auto-generated method stub 128 | return false; 129 | } 130 | @Override 131 | public void setUseWideViewPort(boolean use) { 132 | web_.setUseWideViewPort(use); 133 | } 134 | @Override 135 | public boolean getUseWideViewPort() { 136 | return web_.getUseWideViewPort(); 137 | } 138 | @Override 139 | public void setSupportMultipleWindows(boolean support) { 140 | web_.setSupportMultipleWindows(support); 141 | } 142 | @Override 143 | public boolean supportMultipleWindows() { 144 | return web_.supportMultipleWindows(); 145 | } 146 | @Override 147 | public void setLayoutAlgorithm(LayoutAlgorithm l) { 148 | AwSettings.LayoutAlgorithm algorithm = AwSettings.LayoutAlgorithm.NORMAL; 149 | switch(l) { 150 | case NORMAL: 151 | algorithm = AwSettings.LayoutAlgorithm.NORMAL; 152 | case SINGLE_COLUMN: 153 | algorithm = AwSettings.LayoutAlgorithm.SINGLE_COLUMN; 154 | case NARROW_COLUMNS: 155 | algorithm = AwSettings.LayoutAlgorithm.NARROW_COLUMNS; 156 | } 157 | web_.setLayoutAlgorithm(algorithm); 158 | } 159 | @Override 160 | public LayoutAlgorithm getLayoutAlgorithm() { 161 | switch (web_.getLayoutAlgorithm()) { 162 | case NORMAL: 163 | return LayoutAlgorithm.NORMAL; 164 | case SINGLE_COLUMN: 165 | return LayoutAlgorithm.SINGLE_COLUMN; 166 | case NARROW_COLUMNS: 167 | return LayoutAlgorithm.NARROW_COLUMNS; 168 | case TEXT_AUTOSIZING: 169 | return LayoutAlgorithm.NORMAL; 170 | default: 171 | return LayoutAlgorithm.NORMAL; 172 | } 173 | } 174 | @Override 175 | public void setStandardFontFamily(String font) { 176 | web_.setStandardFontFamily(font); 177 | } 178 | @Override 179 | public String getStandardFontFamily() { 180 | return web_.getStandardFontFamily(); 181 | } 182 | @Override 183 | public void setFixedFontFamily(String font) { 184 | web_.setFixedFontFamily(font); 185 | } 186 | @Override 187 | public String getFixedFontFamily() { 188 | return getFixedFontFamily(); 189 | } 190 | @Override 191 | public void setSansSerifFontFamily(String font) { 192 | web_.setSansSerifFontFamily(font); 193 | } 194 | @Override 195 | public String getSansSerifFontFamily() { 196 | return web_.getSansSerifFontFamily(); 197 | } 198 | @Override 199 | public void setSerifFontFamily(String font) { 200 | web_.setSerifFontFamily(font); 201 | } 202 | @Override 203 | public String getSerifFontFamily() { 204 | return web_.getSerifFontFamily(); 205 | } 206 | @Override 207 | public void setCursiveFontFamily(String font) { 208 | web_.setCursiveFontFamily(font); 209 | } 210 | @Override 211 | public String getCursiveFontFamily() { 212 | return web_.getCursiveFontFamily(); 213 | } 214 | @Override 215 | public void setFantasyFontFamily(String font) { 216 | web_.setFantasyFontFamily(font); 217 | } 218 | @Override 219 | public String getFantasyFontFamily() { 220 | return web_.getFantasyFontFamily(); 221 | } 222 | @Override 223 | public void setMinimumFontSize(int size) { 224 | web_.setMinimumFontSize(size); 225 | } 226 | @Override 227 | public int getMinimumFontSize() { 228 | return web_.getMinimumFontSize(); 229 | } 230 | @Override 231 | public void setMinimumLogicalFontSize(int size) { 232 | web_.setMinimumLogicalFontSize(size); 233 | } 234 | @Override 235 | public int getMinimumLogicalFontSize() { 236 | return web_.getMinimumLogicalFontSize(); 237 | } 238 | @Override 239 | public void setDefaultFontSize(int size) { 240 | web_.setDefaultFontSize(size); 241 | } 242 | @Override 243 | public int getDefaultFontSize() { 244 | return web_.getDefaultFontSize(); 245 | } 246 | @Override 247 | public void setDefaultFixedFontSize(int size) { 248 | web_.setDefaultFixedFontSize(size); 249 | } 250 | @Override 251 | public int getDefaultFixedFontSize() { 252 | return web_.getDefaultFixedFontSize(); 253 | } 254 | @Override 255 | public void setLoadsImagesAutomatically(boolean flag) { 256 | web_.setLoadsImagesAutomatically(flag); 257 | } 258 | @Override 259 | public boolean getLoadsImagesAutomatically() { 260 | return web_.getLoadsImagesAutomatically(); 261 | } 262 | @Override 263 | public void setBlockNetworkImage(boolean flag) { 264 | // TODO Auto-generated method stub 265 | } 266 | @Override 267 | public boolean getBlockNetworkImage() { 268 | // TODO Auto-generated method stub 269 | return false; 270 | } 271 | @Override 272 | public void setBlockNetworkLoads(boolean flag) { 273 | web_.setBlockNetworkLoads(flag); 274 | } 275 | @Override 276 | public boolean getBlockNetworkLoads() { 277 | return web_.getBlockNetworkLoads(); 278 | } 279 | @SuppressLint("SetJavaScriptEnabled") 280 | @Override 281 | public void setJavaScriptEnabled(boolean flag) { 282 | web_.setJavaScriptEnabled(flag); 283 | } 284 | @Override 285 | public void setAllowUniversalAccessFromFileURLs(boolean flag) { 286 | web_.setAllowUniversalAccessFromFileURLs(flag); 287 | } 288 | @Override 289 | public void setAllowFileAccessFromFileURLs(boolean flag) { 290 | web_.setAllowFileAccessFromFileURLs(flag); 291 | } 292 | @Override 293 | public void setPluginState(PluginState state) { 294 | web_.setPluginState(state); 295 | } 296 | @Override 297 | public void setDatabasePath(String databasePath) { 298 | // TODO Auto-generated method stub 299 | } 300 | @Override 301 | public void setGeolocationDatabasePath(String databasePath) { 302 | // TODO Auto-generated method stub 303 | } 304 | @Override 305 | public void setAppCacheEnabled(boolean flag) { 306 | web_.setAppCacheEnabled(flag); 307 | } 308 | @Override 309 | public void setAppCachePath(String appCachePath) { 310 | web_.setAppCachePath(appCachePath); 311 | } 312 | @Override 313 | public void setAppCacheMaxSize(long appCacheMaxSize) { 314 | // TODO Auto-generated method stub 315 | } 316 | @Override 317 | public void setDatabaseEnabled(boolean flag) { 318 | web_.setDatabaseEnabled(flag); 319 | } 320 | @Override 321 | public void setDomStorageEnabled(boolean flag) { 322 | web_.setDomStorageEnabled(flag); 323 | } 324 | @Override 325 | public boolean getDomStorageEnabled() { 326 | return web_.getDomStorageEnabled(); 327 | } 328 | @Override 329 | public String getDatabasePath() { 330 | // TODO Auto-generated method stub 331 | return null; 332 | } 333 | @Override 334 | public boolean getDatabaseEnabled() { 335 | return web_.getDatabaseEnabled(); 336 | } 337 | @Override 338 | public void setGeolocationEnabled(boolean flag) { 339 | web_.setGeolocationEnabled(flag); 340 | } 341 | @Override 342 | public boolean getJavaScriptEnabled() { 343 | return contents_.getJavaScriptEnabled(); 344 | } 345 | @Override 346 | public boolean getAllowUniversalAccessFromFileURLs() { 347 | return web_.getAllowUniversalAccessFromFileURLs(); 348 | } 349 | @Override 350 | public boolean getAllowFileAccessFromFileURLs() { 351 | return web_.getAllowFileAccessFromFileURLs(); 352 | } 353 | @Override 354 | public PluginState getPluginState() { 355 | return web_.getPluginState(); 356 | } 357 | @Override 358 | public void setJavaScriptCanOpenWindowsAutomatically(boolean flag) { 359 | web_.setJavaScriptCanOpenWindowsAutomatically(flag); 360 | } 361 | @Override 362 | public boolean getJavaScriptCanOpenWindowsAutomatically() { 363 | return web_.getJavaScriptCanOpenWindowsAutomatically(); 364 | } 365 | @Override 366 | public void setDefaultTextEncodingName(String encoding) { 367 | web_.setDefaultTextEncodingName(encoding); 368 | } 369 | @Override 370 | public String getDefaultTextEncodingName() { 371 | return web_.getDefaultTextEncodingName(); 372 | } 373 | @Override 374 | public void setUserAgentString(String ua) { 375 | web_.setUserAgentString(ua); 376 | } 377 | @Override 378 | public String getUserAgentString() { 379 | return web_.getUserAgentString(); 380 | } 381 | @Override 382 | public void setNeedInitialFocus(boolean flag) { 383 | // TODO Auto-generated method stub 384 | } 385 | @Override 386 | public void setRenderPriority(RenderPriority priority) { 387 | // TODO Auto-generated method stub 388 | } 389 | @Override 390 | public void setCacheMode(int mode) { 391 | web_.setCacheMode(mode); 392 | } 393 | @Override 394 | public int getCacheMode() { 395 | return web_.getCacheMode(); 396 | } 397 | } 398 | -------------------------------------------------------------------------------- /src/us/costan/chrome/impl/ChromeSslErrorHandlerProxy.java: -------------------------------------------------------------------------------- 1 | package us.costan.chrome.impl; 2 | 3 | import us.costan.chrome.ChromeSslErrorHandler; 4 | import android.webkit.ValueCallback; 5 | 6 | /** 7 | * Proxies from ChromeSslErrorHandler to ValueCallback. 8 | * 9 | * @hide 10 | */ 11 | public class ChromeSslErrorHandlerProxy implements ChromeSslErrorHandler { 12 | /** The proxy target. */ 13 | private ValueCallback target_; 14 | 15 | public ChromeSslErrorHandlerProxy(ValueCallback target) { 16 | target_ = target; 17 | } 18 | @Override 19 | public void cancel() { 20 | target_.onReceiveValue(false); 21 | } 22 | @Override 23 | public void proceed() { 24 | target_.onReceiveValue(true); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /vm/README.md: -------------------------------------------------------------------------------- 1 | # VM Setup Instructions 2 | 3 | [pwnall/chromeview](https://github.com/pwnall/chromeview) includes some 4 | Chromium bits whose build process requires a non-trivial amount of resources 5 | (4Gb RAM, 40Gb disk, fast CPUs or time). Chromium's build process has very 6 | specific requirements, and the Android target adds a bunch more specific 7 | requirements, so the least painful way of getting the build working appears to 8 | be setting up a VM with the exact software that the build process was designed 9 | for. 10 | 11 | This document contains step-by-step instructions for setting up the build VM 12 | and building the files used by ChromeView. 13 | 14 | 15 | ## VM Building 16 | 17 | These are the manual steps for setting up a VM. They only need to be done once. 18 | 19 | 1. Get the 64-bit ISO for Ubuntu Server 12.04 20 | * Go to http://releases.ubuntu.com/12.04/ 21 | * Get the `64-bit PC (AMD64) server install image` 22 | 23 | 2. Set up a VirtualBox VM. 24 | * Name: ChromeWebView 25 | * Type: Linux 26 | * Version: Ubuntu 64-bit 27 | * RAM: 4096Mb 28 | * Disk: VDI, dynamic, 48Gb 29 | 30 | 3. Change the settings (Machine > Settings in the VirtualBox menu) 31 | * System > Processor > Processor(s): 4 (number of CPU cores on the machine) 32 | * Audio > uncheck Enable Audio 33 | * Network > Adapter 1 > Advanced > Adapter Type: virtio-net 34 | * Network > Adapter 2 35 | * check Enable network adapter 36 | * Attached to > Host-only Adapter 37 | * Advanced > Adapter Type: virtio-net 38 | * Ports > USB > uncheck Enable USB 2.0 (EHCI) Controller 39 | 40 | 4. Start VM and set up the server. 41 | * Select the Ubuntu ISO downloaded earlier. 42 | * Start a server installation, providing default answers, except: 43 | * Hostname: crbuild 44 | * Full name: crbuild 45 | * Username: crbuild 46 | * Password: crbuild 47 | * Confirm using a weak password 48 | * Encrypt home directory: no 49 | * Partitioning: Guided - use entire disk (no LVM or encryption) 50 | * Software to install: OpenSSH server 51 | 52 | 6. After the VM restarts, set up networking. 53 | * Log in using the VM console. 54 | * Open /etc/network/interfaces in a text editor (sudo vim ...) 55 | * Duplicate the "primary network interface" section 56 | * In the duplicate section, replace-all eth0 with eth1, primary with 57 | secondary 58 | * Save the file. 59 | * `sudo apt-get install -y avahi-daemon` 60 | * `sudo reboot` 61 | 62 | 7. Prepare to SSH into the VM. 63 | * If you don't have an ssh key 64 | * `ssh-keygen -t rsa` 65 | * press Enter all the way (default key type, no passphrase) 66 | 67 | ```bash 68 | ssh-copy-id crbuild@crbuild.local 69 | ssh crbuild@crbuild.local 70 | ``` 71 | 72 | 8. Get the Oracle Java 6 JDK. 73 | * Go to http://www.oracle.com/technetwork/java/javase/downloads/index.html 74 | * Search for "Java SE 6", click on JDK 75 | * Click on the radio button for accepting the license 76 | * Download the Linux x86 non-RPM file (jdk-6uNN-linux-x64.bin) 77 | 78 | ```bash 79 | exit # Get out of the VM ssh session, run this on the host. 80 | scp ~/Downloads/jdk-6u*-linux-x64.bin crbuild@crbuild.local:~/jdk6.bin 81 | ``` 82 | 83 | 9. If the VM is on a VM server, install and use `mosh` instead of `ssh`. 84 | 85 | ```bash 86 | # ssh crbuild@crbuild.local 87 | sudo apt-get install -y mosh 88 | exit 89 | mosh crbuild@crbuild.local 90 | ``` 91 | 92 | 10. Set up the VM builds target platform(s). Choosing more than one platform 93 | will result in no incremental building being done. 94 | 95 | ```bash 96 | # ssh crbuild@crbuild.local 97 | touch ~/.build_arm 98 | touch ~/.build_x86 99 | ``` 100 | 101 | 11. Optionally set the path of the directory that will hold the Chromium source 102 | code to. This is only used the first time the setup script runs, so it only 103 | needs to be set once. 104 | 105 | ```bash 106 | export CRBUILD_DIR=/mnt/crbuild 107 | ``` 108 | 109 | ### Building on Amazon EC2 110 | 111 | This setup has been tested on OpenStack, using a 64-bit 112 | [Ubuntu 12.04LTS cloud image](http://cloud-images.ubuntu.com/releases/lucid/release/), 113 | and will likely work on Amazon EC2 as well. 114 | 115 | When using a VM server, open the following ports on the VM. 116 | 117 | * TCP 22 - ssh 118 | * TCP 80 - http, for downloading builds 119 | * UDP 60000:610000 - mosh, because ssh seems to break down during chrome builds 120 | 121 | 122 | ## VM Setup 123 | 124 | The setup script will complete the work done above. The script is idempotent, 125 | so it can be ran to bring a VM's software up to date. 126 | 127 | ```bash 128 | # ssh crbuild@crbuild.local 129 | curl -fLsS https://github.com/pwnall/chromeview-src/raw/master/vm/setup.sh | bash 130 | ``` 131 | 132 | If the script fails, the steps in [setup.sh](vm/setup.sh) can be 133 | copy-pasted one by one in the VM's ssh console. Please open an issue or pull 134 | request if the script fails. 135 | 136 | The VM should be rebooted after the first time this script runs. 137 | 138 | ```bash 139 | # ssh crbuild@crbuild.local 140 | sudo reboot 141 | ``` 142 | 143 | If this is the first time the Chromium source code is downloaded and 144 | `$CRBUILD_DIR` is defined, the directory at that path will be created and 145 | symlinked into `~/chromium`. The source code can be moved around, as long as 146 | the symlink is updated. 147 | 148 | 149 | ## Building 150 | 151 | The build script will update the Chromium source code and do a build. If builds 152 | are done infrequently, the setup script above should be ran before every build. 153 | 154 | ```bash 155 | # ssh crbuild@crbuild.local 156 | curl -fLsS https://github.com/pwnall/chromeview-src/raw/master/vm/build.sh | bash 157 | ``` 158 | 159 | The build results can be downloaded by visiting the VM's IP address in a Web 160 | browser. 161 | -------------------------------------------------------------------------------- /vm/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Builds the Chromium bits needed by ChromeView. 3 | 4 | set -o errexit # Stop the script on the first error. 5 | set -o nounset # Catch un-initialized variables. 6 | 7 | # Prepare the output area. 8 | mkdir -p ~/crbuild.www/archives 9 | mkdir -p ~/crbuild.www/staging 10 | mkdir -p ~/crbuild.www/logs 11 | 12 | # Build Chromium. 13 | # https://code.google.com/p/chromium/wiki/UsingGit 14 | if [ ! -z GCLIENT_SYNC ] ; then 15 | cd ~/chromium/src 16 | git checkout lkgr 17 | git pull 18 | gclient sync --force --delete_unversioned_trees 19 | fi 20 | 21 | cd ~/chromium/src 22 | echo "Building $(git rev-parse HEAD)" 23 | 24 | CPUS=$(grep -c 'processor' /proc/cpuinfo) 25 | 26 | if [ -f ~/.build_arm ] ; then 27 | set +o nounset # Chromium scripts are messy. 28 | # NOTE: "source" is bash-only, "." is POSIX. 29 | . build/android/envsetup.sh --target-arch=arm 30 | set -o nounset # Catch un-initialized variables. 31 | android_gyp 32 | ninja -C out/Release -k0 -j$CPUS libwebviewchromium android_webview_apk \ 33 | content_shell_apk chromium_testshell 34 | fi 35 | 36 | if [ -f ~/.build_x86 ] ; then 37 | set +o nounset # Chromium scripts are messy. 38 | . build/android/envsetup.sh --target-arch=x86 39 | set -o nounset # Catch un-initialized variables. 40 | android_gyp 41 | ninja -C out/Release -k0 -j$CPUS libwebviewchromium android_webview_apk \ 42 | content_shell_apk chromium_testshell 43 | fi 44 | 45 | 46 | # Package the build. 47 | cd ~/chromium/src 48 | REV=$(git rev-parse HEAD) 49 | STAGING=~/crbuild.www/staging/$REV 50 | rm -rf $STAGING 51 | mkdir -p $STAGING 52 | 53 | # Structure. 54 | mkdir -p $STAGING/assets 55 | mkdir -p $STAGING/libs 56 | mkdir -p $STAGING/res 57 | mkdir -p $STAGING/src 58 | 59 | 60 | # ContentShell core -- use this if android_webview doesn't work out. 61 | #scp out/Release/content_shell/assets/* assets/ 62 | #scp -r out/Release/content_shell_apk/libs/* libs/ 63 | #scp -r content/shell/android/java/res/* ~/crbuilds/$REV/res/ 64 | #scp -r content/shell/android/java/src/* ~/crbuilds/$REV/src/ 65 | #scp -r content/shell_apk/android/java/res/* ~/crbuilds/$REV/res/ 66 | 67 | # android_webview 68 | cp out/Release/android_webview_apk/assets/*.pak $STAGING/assets/ 69 | cp -r out/Release/android_webview_apk/libs/* $STAGING/libs/ 70 | rm $STAGING/libs/**/gdbserver 71 | cp -r android_webview/java/src/* $STAGING/src/ 72 | 73 | ## Dependencies inferred from android_webview/Android.mk 74 | 75 | # Resources. 76 | mkdir -p $STAGING/res2/ 77 | cp -r ui/android/java/res/* $STAGING/res2/ 78 | rename 's/\.xml$/_android_ui.xml/' $STAGING/res2/values*/*.xml 79 | cp -r $STAGING/res2/* $STAGING/res/ 80 | rm -rf $STAGING/res2 81 | 82 | mkdir -p $STAGING/res2/ 83 | cp -r chrome/android/java/res/* $STAGING/res2/ 84 | rename 's/\.xml$/_android_chrome.xml/' $STAGING/res2/values*/*.xml 85 | cp -r $STAGING/res2/* $STAGING/res/ 86 | rm -rf $STAGING/res2 87 | 88 | mkdir -p $STAGING/res2/ 89 | cp -r content/public/android/java/res/* $STAGING/res2/ 90 | rename 's/\.xml$/_android_content.xml/' $STAGING/res2/values*/*.xml 91 | cp -r $STAGING/res2/* $STAGING/res/ 92 | rm -rf $STAGING/res2 93 | 94 | mkdir -p $STAGING/res2/ 95 | cp -r content/shell/android/java/res/* $STAGING/res2/ 96 | rename 's/\.xml$/_android_content_shell.xml/' $STAGING/res2/values*/*.xml 97 | cp -r $STAGING/res2/* $STAGING/res/ 98 | rm -rf $STAGING/res2 99 | 100 | # Generated string resources. 101 | mkdir -p $STAGING/res/values 102 | cp -r ./out/Release/gen/ui_java/res_grit/values/* $STAGING/res/values 103 | cp -r ./out/Release/gen/chrome_java/res_grit/values/* $STAGING/res/values 104 | cp -r ./out/Release/gen/content_java/res_grit/values/* $STAGING/res/values 105 | 106 | 107 | # ContentView dependencies. 108 | cp -r base/android/java/src/* $STAGING/src/ 109 | cp -r content/public/android/java/src/* $STAGING/src/ 110 | cp -r media/base/android/java/src/* $STAGING/src/ 111 | cp -r net/android/java/src/* $STAGING/src/ 112 | cp -r ui/android/java/src/* $STAGING/src/ 113 | cp -r third_party/eyesfree/src/android/java/src/* $STAGING/src/ 114 | 115 | # Strip a ContentView file that's not supposed to be here. 116 | rm $STAGING/src/org/chromium/content/common/common.aidl 117 | 118 | # Get rid of the version control directory in eyesfree. 119 | rm -rf $STAGING/src/com/googlecode/eyesfree/braille/.svn 120 | rm -rf $STAGING/src/com/googlecode/eyesfree/braille/.git 121 | 122 | # Browser components. 123 | cp -r components/web_contents_delegate_android/android/java/src/* $STAGING/src/ 124 | cp -r components/navigation_interception/android/java/src/* $STAGING/src/ 125 | cp -r components/autofill/core/browser/android/java/src/* $STAGING/src/ 126 | 127 | # Generated files. 128 | cp -r out/Release/gen/templates/* $STAGING/src/ 129 | 130 | # JARs. 131 | cp -r out/Release/lib.java/guava_javalib.jar $STAGING/libs/ 132 | cp -r out/Release/lib.java/jsr_305_javalib.jar $STAGING/libs/ 133 | 134 | # android_webview generated sources. Must come after all the other sources. 135 | cp -r android_webview/java/generated_src/* $STAGING/src/ 136 | 137 | # Archive. 138 | ARCHIVE="archives/$REV" 139 | if [ -f ~/.build_arm ] ; then 140 | ARCHIVE="$ARCHIVE-arm" 141 | fi 142 | if [ -f ~/.build_x86 ] ; then 143 | ARCHIVE="$ARCHIVE-x86" 144 | fi 145 | cd $STAGING 146 | tar -czvf "$HOME/crbuild.www/$ARCHIVE.tar.gz" . 147 | 148 | # Clean up the build directory. 149 | cd ~/crbuild.www 150 | rm -rf $STAGING 151 | 152 | # Update the latest-build info. 153 | echo -n $REV > ~/crbuild.www/LATEST_REV 154 | echo -n $ARCHIVE.tar.gz > ~/crbuild.www/LATEST 155 | -------------------------------------------------------------------------------- /vm/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Idempotent VM setup / upgrade script. 3 | 4 | set -o errexit # Stop the script on the first error. 5 | set -o nounset # Catch un-initialized variables. 6 | 7 | # Enable password-less sudo for the current user. 8 | sudo sh -c "echo '$USER ALL=(ALL:ALL) NOPASSWD: ALL' > /etc/sudoers.d/$USER" 9 | sudo chmod 0400 /etc/sudoers.d/$USER 10 | 11 | # Sun JDK 6. 12 | if [ ! -f /usr/bin/javac ] ; then 13 | if [ ! -f ~/jdk6.bin ] ; then 14 | echo 'Please download the Linux x86 non-RPM JDK6 as jdk6.bin from' 15 | echo 'http://www.oracle.com/technetwork/java/javase/downloads/index.html' 16 | exit 1 17 | fi 18 | 19 | sudo mkdir -p /usr/lib/jvm 20 | cd /usr/lib/jvm 21 | sudo /bin/sh ~/jdk6.bin -noregister 22 | rm ~/jdk6.bin 23 | sudo update-alternatives --install /usr/bin/javac javac \ 24 | /usr/lib/jvm/jdk1.6.0_*/bin/javac 50000 25 | sudo update-alternatives --config javac 26 | sudo update-alternatives --install /usr/bin/java java \ 27 | /usr/lib/jvm/jdk1.6.0_*/bin/java 50000 28 | sudo update-alternatives --config java 29 | sudo update-alternatives --install /usr/bin/javaws javaws \ 30 | /usr/lib/jvm/jdk1.6.0_*/bin/javaws 50000 31 | sudo update-alternatives --config javaws 32 | sudo update-alternatives --install /usr/bin/javap javap \ 33 | /usr/lib/jvm/jdk1.6.0_*/bin/javap 50000 34 | sudo update-alternatives --config javap 35 | sudo update-alternatives --install /usr/bin/jar jar \ 36 | /usr/lib/jvm/jdk1.6.0_*/bin/jar 50000 37 | sudo update-alternatives --config jar 38 | sudo update-alternatives --install /usr/bin/jarsigner jarsigner \ 39 | /usr/lib/jvm/jdk1.6.0_*/bin/jarsigner 50000 40 | sudo update-alternatives --config jarsigner 41 | cd ~/ 42 | fi 43 | 44 | # When upgrading, keep modified configuration files, overwrite unmodified ones. 45 | sudo tee /etc/apt/apt.conf.d/90-no-prompt > /dev/null <<'EOF' 46 | Dpkg::Options { 47 | "--force-confdef"; 48 | "--force-confold"; 49 | } 50 | EOF 51 | 52 | # Enable the multiverse reposistory, for ttf-mscorefonts-installer. 53 | sudo sed -i "/^# deb.*multiverse/ s/^# //" /etc/apt/sources.list 54 | 55 | # Update all system packages. 56 | sudo apt-get update -qq 57 | sudo apt-get -y dist-upgrade 58 | 59 | # debconf-get-selections is useful for figuring out debconf defaults. 60 | sudo apt-get install -y debconf-utils 61 | 62 | # Quiet all package installation prompts. 63 | sudo debconf-set-selections <<'EOF' 64 | debconf debconf/frontend select Noninteractive 65 | debconf debconf/priority select critical 66 | EOF 67 | 68 | # Web server for the builds. 69 | sudo apt-get install -y apache2 70 | sudo mkdir -p /etc/apache2/sites-available 71 | sudo tee /etc/apache2/sites-available/001-crbuilds.conf > /dev/null < 73 | ServerAdmin webmaster@localhost 74 | 75 | DocumentRoot /home/$USER/crbuild.www 76 | 77 | Options FollowSymLinks 78 | AllowOverride None 79 | 80 | 81 | Options Indexes FollowSymLinks MultiViews 82 | AllowOverride None 83 | Order allow,deny 84 | allow from all 85 | 86 | 87 | ErrorLog /var/log/apache2/error.log 88 | LogLevel warn 89 | CustomLog /var/log/apache2/access.log combined 90 | 91 | EOF 92 | sudo ln -s -f /etc/apache2/sites-available/001-crbuilds.conf \ 93 | /etc/apache2/sites-enabled/001-crbuilds.conf 94 | sudo rm -f /etc/apache2/sites-enabled/*default 95 | sudo /etc/init.d/apache2 restart 96 | 97 | # Git. 98 | sudo apt-get install -y git 99 | 100 | # Depot tools. 101 | # http://dev.chromium.org/developers/how-tos/install-depot-tools 102 | cd ~ 103 | if [ -d ~/depot_tools ] ; then 104 | cd ~/depot_tools 105 | git pull origin master 106 | cd ~ 107 | fi 108 | if [ ! -d ~/depot_tools ] ; then 109 | git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git 110 | fi 111 | if ! grep -q 'export PATH=$PATH:$HOME/depot_tools' ~/.bashrc ; then 112 | echo 'export PATH=$PATH:$HOME/depot_tools' >> ~/.bashrc 113 | export PATH=$PATH:$HOME/depot_tools 114 | fi 115 | 116 | # Subversion and git-svn. 117 | sudo apt-get install -y git-svn subversion 118 | 119 | # Chromium build setup. 120 | # https://code.google.com/p/chromium/wiki/LinuxBuildInstructions 121 | # https://code.google.com/p/chromium/wiki/AndroidBuildInstructions 122 | 123 | # Chromium build depedenecies not covered by the Chromium scripts. 124 | sudo apt-get install -y ia32-libs libc6-dev-i386 g++-multilib 125 | 126 | # Chromium source. 127 | # https://code.google.com/p/chromium/wiki/UsingGit 128 | # http://dev.chromium.org/developers/how-tos/get-the-code 129 | if [ ! -d ~/chromium ] ; then 130 | if [ ! -z $CRBUILD_DIR ] ; then 131 | sudo mkdir -p "$CRBUILD_DIR" 132 | sudo mkdir -p "$CRBUILD_DIR/chromium" 133 | sudo mkdir -p "$CRBUILD_DIR/crbuild.www" 134 | sudo chown $USER "$CRBUILD_DIR" 135 | sudo chown $USER "$CRBUILD_DIR/chromium" 136 | sudo chown $USER "$CRBUILD_DIR/crbuild.www" 137 | chmod 0755 "$CRBUILD_DIR" 138 | chmod 0755 "$CRBUILD_DIR/chromium" 139 | chmod 0755 "$CRBUILD_DIR/crbuild.www" 140 | ln -s "$CRBUILD_DIR/chromium" ~/chromium 141 | ln -s "$CRBUILD_DIR/crbuild.www" ~/crbuild.www 142 | fi 143 | if [ -z "$CRBUILD_DIR" ] ; then 144 | mkdir -p ~/chromium 145 | mkdir -p ~/crbuild.www 146 | fi 147 | fi 148 | cd ~/chromium 149 | if [ ! -f .gclient ] ; then 150 | ~/depot_tools/fetch android --nosvn=True || \ 151 | echo "Ignore the error above if this is a first-time setup" 152 | fi 153 | cd ~/chromium/src 154 | sudo ./build/install-build-deps-android.sh 155 | yes | sudo ./build/install-build-deps.sh --no-syms --arm --lib32 156 | 157 | cd ~/chromium 158 | 159 | set +o nounset # Chromium scripts are messy. 160 | . src/build/android/envsetup.sh # "source" is bash-only, whereas "." is POSIX. 161 | set -o nounset # Catch un-initialized variables. 162 | gclient runhooks || \ 163 | echo "Ignore the error above if this is a first-time setup" 164 | --------------------------------------------------------------------------------