7 package com.google.appinventor.components.runtime;
9 import android.Manifest;
10 import android.graphics.Bitmap;
11 import android.view.MotionEvent;
12 import android.view.View;
13 import android.webkit.CookieManager;
14 import android.webkit.JavascriptInterface;
15 import android.webkit.WebView;
16 import android.webkit.WebViewClient;
81 @DesignerComponent(version = YaVersion.WEBVIEWER_COMPONENT_VERSION,
82 category = ComponentCategory.USERINTERFACE,
83 description =
"Component for viewing Web pages. The Home URL can be " +
84 "specified in the Designer or in the Blocks Editor. The view can be set " +
85 "to follow links when they are tapped, and users can fill in Web forms. " +
86 "Warning: This is not a full browser. For example, pressing the phone's " +
87 "hardware Back key will exit the app, rather than move back in the " +
89 "<p />You can use the WebViewer.WebViewString property to communicate " +
90 "between your app and Javascript code running in the Webviewer page. " +
91 "In the app, you get and set WebViewString. " +
92 "In the WebViewer, you include Javascript that references the window.AppInventor " +
93 "object, using the methoods </em getWebViewString()</em> and <em>setWebViewString(text)</em>. " +
94 "<p />For example, if the WebViewer opens to a page that contains the Javascript command " +
95 "<br /> <em>document.write(\"The answer is\" + window.AppInventor.getWebViewString());</em> " +
96 "<br />and if you set WebView.WebVewString to \"hello\", then the web page will show " +
97 "</br ><em>The answer is hello</em>. " +
98 "<br />And if the Web page contains Javascript that executes the command " +
99 "<br /><em>window.AppInventor.setWebViewString(\"hello from Javascript\")</em>, " +
100 "<br />then the value of the WebViewString property will be " +
101 "<br /><em>hello from Javascript</em>. ")
106 @UsesPermissions(permissionNames =
"android.permission.INTERNET")
109 private final WebView webview;
112 private String homeUrl;
115 private boolean followLinks =
true;
118 private boolean prompt =
true;
123 private boolean ignoreSslErrors =
false;
129 private boolean havePermission =
false;
139 webview =
new WebView(container.
$context());
140 resetWebViewClient();
141 webview.getSettings().setJavaScriptEnabled(
true);
142 webview.setFocusable(
true);
145 webview.addJavascriptInterface(wvInterface,
"AppInventor");
147 webview.getSettings().setBuiltInZoomControls(
true);
152 container.
$add(
this);
154 webview.setOnTouchListener(
new View.OnTouchListener() {
156 public boolean onTouch(View v, MotionEvent event) {
157 switch (event.getAction()) {
158 case MotionEvent.ACTION_DOWN:
159 case MotionEvent.ACTION_UP:
173 Width(LENGTH_FILL_PARENT);
174 Height(LENGTH_FILL_PARENT);
183 @
SimpleProperty(description =
"Gets the WebView's String, which is viewable through " +
184 "Javascript in the WebView as the window.AppInventor object",
186 public String WebViewString() {
196 public
void WebViewString(String newString) {
210 private class WebViewerClient
extends WebViewClient {
212 public boolean shouldOverrideUrlLoading(WebView view, String url) {
217 public void onPageStarted(WebView view, String url, Bitmap favicon) {
222 public void onPageFinished(WebView view, String url) {
227 public void onReceivedError(WebView view,
final int errorCode,
final String description,
final String failingUrl) {
228 container.$form().runOnUiThread(
new Runnable() {
230 ErrorOccurred(errorCode, description, failingUrl);
245 public
void Width(
int width) {
246 if (width == LENGTH_PREFERRED) {
247 width = LENGTH_FILL_PARENT;
258 public
void Height(
int height) {
259 if (height == LENGTH_PREFERRED) {
260 height = LENGTH_FILL_PARENT;
262 super.Height(height);
272 description =
"URL of the page the WebViewer should initially open to. " +
273 "Setting this will load the page.",
275 public String HomeUrl() {
288 public
void HomeUrl(String url) {
291 webview.clearHistory();
292 loadUrl(
"HomeUrl", homeUrl);
302 description =
"URL of the page currently viewed. This could be different from the " +
303 "Home URL if new pages were visited by following links.",
305 public String CurrentUrl() {
306 return (webview.getUrl() ==
null) ?
"" : webview.getUrl();
315 description =
"Title of the page currently viewed",
317 public String CurrentPageTitle() {
318 return (webview.getTitle() ==
null) ?
"" : webview.getTitle();
326 description =
"Determines whether to follow links when they are tapped in the WebViewer. " +
327 "If you follow links, you can use GoBack and GoForward to navigate the browser history. ",
329 public
boolean FollowLinks() {
340 defaultValue =
"True")
342 public
void FollowLinks(
boolean follow) {
343 followLinks = follow;
344 resetWebViewClient();
355 description =
"Determine whether or not to ignore SSL errors. Set to true to ignore " +
356 "errors. Use this to accept self signed certificates from websites.",
358 public
boolean IgnoreSslErrors() {
359 return ignoreSslErrors;
369 defaultValue =
"False")
371 public
void IgnoreSslErrors(
boolean ignoreSslErrors) {
372 this.ignoreSslErrors = ignoreSslErrors;
373 resetWebViewClient();
381 description =
"Loads the home URL page. This happens automatically when " +
382 "the home URL is changed.")
383 public
void GoHome() {
384 loadUrl(
"GoHome", homeUrl);
391 description =
"Go back to the previous page in the history list. " +
392 "Does nothing if there is no previous page.")
393 public
void GoBack() {
394 if (webview.canGoBack()) {
403 description =
"Go forward to the next page in the history list. " +
404 "Does nothing if there is no next page.")
405 public
void GoForward() {
406 if (webview.canGoForward()) {
415 description =
"Returns true if the WebViewer can go forward in the history list.")
416 public
boolean CanGoForward() {
417 return webview.canGoForward();
425 description =
"Returns true if the WebViewer can go back in the history list.")
426 public
boolean CanGoBack() {
427 return webview.canGoBack();
435 description =
"Load the page at the given URL.")
436 public
void GoToUrl(String url) {
437 loadUrl(
"GoToUrl", url);
444 description =
"Stop loading a page.")
445 public
void StopLoading() {
446 webview.stopLoading();
453 description =
"Reload the current page.")
454 public
void Reload() {
465 defaultValue =
"False")
467 description =
"Whether or not to give the application permission to use the Javascript geolocation API. " +
468 "This property is available only in the designer.")
469 public
void UsesLocation(
boolean uses) {
480 @
SimpleProperty(description =
"If True, then prompt the user of the WebView to give permission to access the geolocation API. " +
481 "If False, then assume permission is granted.")
482 public
boolean PromptforPermission() {
496 defaultValue =
"True")
498 public
void PromptforPermission(
boolean prompt) {
499 this.prompt = prompt;
511 @
SimpleFunction(description =
"Clear stored location permissions.")
512 public
void ClearLocations() {
517 private void resetWebViewClient() {
521 webview.setWebViewClient(
new WebViewerClient());
530 @SimpleFunction(description =
"Clear WebView caches.")
531 public
void ClearCaches() {
532 webview.clearCache(
true);
540 public
void ClearCookies() {
541 CookieManager cookieManager = CookieManager.getInstance();
543 cookieManager.removeAllCookies(
null);
545 cookieManager.removeAllCookie();
552 @
SimpleFunction(description =
"Run JavaScript in the current page.")
553 public
void RunJavaScript(String js) {
556 webview.loadUrl(
"javascript:(function(){" + js +
"})()");
564 @
SimpleEvent(description =
"When the JavaScript calls AppInventor.setWebViewString this event is run.")
565 public
void WebViewStringChange(String value) {
569 @
SimpleEvent(description =
"When a page is about to load this event is run.")
570 public
void BeforePageLoad(String url) {
574 @
SimpleEvent(description =
"When a page is finished loading this event is run.")
575 public
void PageLoaded(String url) {
579 @
SimpleEvent(description =
"When an error occurs this event is run.")
580 public
void ErrorOccurred(
int errorCode, String description, String failingUrl) {
584 private void loadUrl(
final String caller,
final String url) {
586 container.$form().askPermission(Manifest.permission.READ_EXTERNAL_STORAGE,
589 public void HandlePermissionResponse(String permission,
boolean granted) {
591 havePermission =
true;
592 webview.loadUrl(url);
594 container.$form().dispatchPermissionDeniedEvent(WebViewer.this, caller,
595 Manifest.permission.READ_EXTERNAL_STORAGE);
601 webview.loadUrl(url);
609 String webViewString;
623 return webViewString;
631 webViewString = newString;
633 container.$form().runOnUiThread(
new Runnable() {
635 WebViewStringChange(newString);
641 webViewString = newString;