I'm working on maven web application with JSP and Servlets. I have a href which has a applet class call which loads my applet success fully from certain Servlet but on my windows only. Now I want to load this into client browser wherever this link is clicked from remote machine's IP. Please help me on this it should be loaded on client browser from HTML or JSP.
This is my class in my Java:
package com.enidiris.util;
import javax.swing.JApplet;
import javax.swing.SwingUtilities;
public class AppletIris extends JApplet {
/**
*
*/
private static final long serialVersionUID = 1L;
private boolean inAnApplet = true;
public AppletIris() {
this(true);
}
public AppletIris(boolean inAnApplet) {
this.inAnApplet = inAnApplet;
if (inAnApplet) {
getRootPane().putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE);
}
}
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public void createGUI() {
MainPanel mainPanel = new MainPanel();
getContentPane().add(mainPanel);
}
}
This is my HTML in same web application but nothing says in console of browsers, not even loading applet.
webapp/ register.jsp
<body onload="checkSession();">
<jsp:plugin type="applet" name="AppletIris" code="com.enidiris.util.AppletIris" width="950" height="650" hspace="0" vspace="0" codebase="." >
</jsp:plugin>
<!-- <object codetype="application/java" classid="java:AppletIris.class" -->
<!-- archive="enidiris-applet.jar" width="740" height="400"></object> -->
</body>
Related
Android not displaying camera in WebView.
I have build a WebView application with camera access.
The url loads and it works. but camera does not work in WebView application.
My code is below I have my question is what am I doing wrong. I see no errors but the camera does not open at all .
<!DOCTYPE html>
<html>
<head>
<title>///////</title>
<script type="text/javascript" src="../includes/instascan.min.js"></script>
</head>
<body>
<video id="preview" <?php /* style="position:fixed;right:0;bottom:0;min-width:100%;min-height:100%;" */ ?>></video>
<script type="text/javascript">
let opts = {
// Whether to scan continuously for QR codes. If false, use scanner.scan() to manually scan.
// If true, the scanner emits the "scan" event when a QR code is scanned. Default true.
continuous: true,
// The HTML element to use for the camera's video preview. Must be a <video> element.
// When the camera is active, this element will have the "active" CSS class, otherwise,
// it will have the "inactive" class. By default, an invisible element will be created to
// host the video.
video: document.getElementById('preview'),
// Whether to horizontally mirror the video preview. This is helpful when trying to
// scan a QR code with a user-facing camera. Default true.
mirror: false,
// Whether to include the scanned image data as part of the scan result. See the "scan" event
// for image format details. Default false.
captureImage: false,
// Only applies to continuous mode. Whether to actively scan when the tab is not active.
// When false, this reduces CPU usage when the tab is not active. Default true.
backgroundScan: true,
// Only applies to continuous mode. The period, in milliseconds, before the same QR code
// will be recognized in succession. Default 5000 (5 seconds).
refractoryPeriod: 5000,
// Only applies to continuous mode. The period, in rendered frames, between scans. A lower scan period
// increases CPU usage but makes scan response faster. Default 1 (i.e. analyze every frame).
scanPeriod: 1
};
let scanner = new Instascan.Scanner(opts);
scanner.addListener('scan', function (content) {
window.location = "result.php?result="+content;
});
Instascan.Camera.getCameras().then(function (cameras) {
if (cameras.length > 0) {
if(cameras.length > 1){
scanner.start(cameras[1]);
}
else{
scanner.start(cameras[0]);
}
} else {
console.error('No cameras found.');
}
}).catch(function (e) {
console.error(e);
});
</script>
</body>
</html>
Here is my Android coding :
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0099cc"
tools:context=".FullscreenActivity">
<!-- The primary full-screen view. This can be replaced with whatever view
is needed to present your content, e.g. VideoView, SurfaceView,
TextureView, etc. -->
<TextView
android:id="#+id/fullscreen_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:keepScreenOn="true"
android:text="#string/dummy_content"
android:textColor="#33b5e5"
android:textSize="50sp"
android:textStyle="bold" />
<!-- This FrameLayout insets its children based on system windows using
android:fitsSystemWindows. -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<WebView
android:id="#+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<LinearLayout
android:id="#+id/fullscreen_content_controls"
style="?metaButtonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:background="#color/black_overlay"
android:orientation="horizontal"
tools:ignore="UselessParent">
</LinearLayout>
</FrameLayout>
</FrameLayout>
package //////////?????????;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.PermissionRequest;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*/
public class FullscreenActivity extends AppCompatActivity {
/**
* Whether or not the system UI should be auto-hidden after
* {#link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
*/
private static final boolean AUTO_HIDE = true;
/**
* If {#link #AUTO_HIDE} is set, the number of milliseconds to wait after
* user interaction before hiding the system UI.
*/
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
/**
* Some older devices needs a small delay between UI widget updates
* and a change of the status and navigation bar.
*/
private static final int UI_ANIMATION_DELAY = 300;
private final Handler mHideHandler = new Handler();
private View mContentView;
private final Runnable mHidePart2Runnable = new Runnable() {
#SuppressLint("InlinedApi")
#Override
public void run() {
// Delayed removal of status and navigation bar
// Note that some of these constants are new as of API 16 (Jelly Bean)
// and API 19 (KitKat). It is safe to use them, as they are inlined
// at compile-time and do nothing on earlier devices.
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
};
private View mControlsView;
private final Runnable mShowPart2Runnable = new Runnable() {
#Override
public void run() {
// Delayed display of UI elements
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.show();
}
mControlsView.setVisibility(View.VISIBLE);
}
};
private boolean mVisible;
private final Runnable mHideRunnable = new Runnable() {
#Override
public void run() {
hide();
}
};
/**
* Touch listener to use for in-layout UI controls to delay hiding the
* system UI. This is to prevent the jarring behavior of controls going away
* while interacting with activity UI.
*/
private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (AUTO_HIDE) {
delayedHide(AUTO_HIDE_DELAY_MILLIS);
}
return false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
mVisible = true;
mControlsView = findViewById(R.id.fullscreen_content_controls);
mContentView = findViewById(R.id.fullscreen_content);
// Set up the user interaction to manually show or hide the system UI.
mContentView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
toggle();
}
});
// Upon interacting with UI controls, delay any scheduled hide()
// operations to prevent the jarring behavior of controls going away
// while interacting with the UI.
final WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebChromeClient(new WebChromeClient());
myWebView.setWebViewClient(new WebViewClient() {
public void onPageStarted(WebView view, String url, Bitmap favicon) {
myWebView.setVisibility(View.GONE);
}
#Override
public void onPageFinished(WebView view, String url) {
myWebView.setVisibility(View.VISIBLE);
}
public void onReceivedError(WebView webview, int i, String s, String s1) {
webview.loadUrl("");
}
});
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.getSettings().setPluginState(WebSettings.PluginState.ON);
myWebView.loadUrl("https://www.twsb.co.za/mobile_app/rep/scan.php");
// myWebView.setWebChromeClient(new WebChromeClient(){
// #TargetApi(Build.VERSION_CODES.LOLLIPOP)
// #Override
// public void onPermissionRequest(final PermissionRequest request) {
// request.grant(request.getResources());
// }
// });
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
delayedHide(100);
}
private void toggle() {
if (mVisible) {
hide();
} else {
show();
}
}
private void hide() {
// Hide UI first
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
mControlsView.setVisibility(View.GONE);
mVisible = false;
// Schedule a runnable to remove the status and navigation bar after a delay
mHideHandler.removeCallbacks(mShowPart2Runnable);
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
}
#SuppressLint("InlinedApi")
private void show() {
// Show the system bar
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mVisible = true;
// Schedule a runnable to display UI elements after a delay
mHideHandler.removeCallbacks(mHidePart2Runnable);
mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
}
/**
* Schedules a call to hide() in delay milliseconds, canceling any
* previously scheduled calls.
*/
private void delayedHide(int delayMillis) {
mHideHandler.removeCallbacks(mHideRunnable);
mHideHandler.postDelayed(mHideRunnable, delayMillis);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="??????????????????">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-feature android:name="android.hardware.bluetooth" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".FullscreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name"
android:theme="#style/FullscreenTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
if I load the url separately in my internet browser it works and I can
access the camera. how every not thru the app.
There are two way to implement this feature.
Use native call from webview by javascript method
For more information :
Binding JavaScript code to Android code
Set WebChromeClient in Webview :
For Example:
webView.setWebChromeClient(new WebChromeClient() {
// openFileChooser for Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType){
// Update message
mUploadMessage = uploadMsg;
try{
// Create AndroidExampleFolder at sdcard
File imageStorageDir = new File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES)
, "AndroidExampleFolder");
if (!imageStorageDir.exists()) {
// Create AndroidExampleFolder at sdcard
imageStorageDir.mkdirs();
}
// Create camera captured image file path and name
File file = new File(
imageStorageDir + File.separator + "IMG_"
+ String.valueOf(System.currentTimeMillis())
+ ".jpg");
mCapturedImageURI = Uri.fromFile(file);
// Camera capture image intent
final Intent captureIntent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
// Create file chooser intent
Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
// Set camera intent to file chooser
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS
, new Parcelable[] { captureIntent });
// On select image call onActivityResult method of activity
startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
}
catch(Exception e){
Toast.makeText(getBaseContext(), "Exception:"+e,
Toast.LENGTH_LONG).show();
}
}
// openFileChooser for Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg){
openFileChooser(uploadMsg, "");
}
//openFileChooser for other Android versions
public void openFileChooser(ValueCallback<Uri> uploadMsg,
String acceptType,
String capture) {
openFileChooser(uploadMsg, acceptType);
}
// The webPage has 2 filechoosers and will send a
// console message informing what action to perform,
// taking a photo or updating the file
public boolean onConsoleMessage(ConsoleMessage cm) {
onConsoleMessage(cm.message(), cm.lineNumber(), cm.sourceId());
return true;
}
public void onConsoleMessage(String message, int lineNumber, String sourceID) {
//Log.d("androidruntime", "Show console messages, Used for debugging: " + message);
}
}); // End setWebChromeClient
Return here when file selected from camera or from SDcard
#Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if(requestCode==FILECHOOSER_RESULTCODE)
{
if (null == this.mUploadMessage) {
return;
}
Uri result=null;
try{
if (resultCode != RESULT_OK) {
result = null;
} else {
// retrieve from the private variable if the intent is null
result = intent == null ? mCapturedImageURI : intent.getData();
}
}
catch(Exception e)
{
Toast.makeText(getApplicationContext(), "activity :"+e,
Toast.LENGTH_LONG).show();
}
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
Add filepath code for API Level 25.
I am currently working on a Java application that uses a JavaFX webview to display its UI (with HTML/CSS).
Everything is working fine but I have trouble loading a new page in the system. When I do, the communication between the Java and the new page's JavaScript seems to be broken.
Here is my code :
** Broser **
public class Browser extends Region {
final WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
public Browser() {
//apply the styles
getStyleClass().add("browser");
// load the web page
webEngine.load(some_url);
JSObject jsobj = (JSObject) webEngine.executeScript("window");
Bridge bridge = Bridge.getInstance();
bridge.init(webEngine);
jsobj.setMember("java", bridge);
//add the web view to the scene
getChildren().add(browser);
}
}
** Bridge **
public class Bridge {
private static Bridge instance = null;
private WebEngine webEngine;
public Bridge () {
}
public static Bridge getInstance() {
if(instance == null){
instance = new Bridge();
}
return instance;
}
public void init(WebEngine webEngine) {
if(this.webEngine == null) {
this.webEngine = webEngine;
}
}
public void btnStartSessionOnClick(String sessionName, String speakerNickname) {
// Load the new page
webEngine.load(some_other_url);
}
}
Whenever the web engine loads a new page, it replaces the DOM, so there is a different window object. The jsobj you define is only set once, so when a new page is loaded it will be pointing to the wrong object. You need to reset this object every time the page loads, which you can do by observing the engine's load state.
Your design doesn't make a whole lot of sense to me: it makes more sense to me to have the window (jsobj) object as part of the Bridge class, rather than the application class. And since the Browser is not a singleton, it doesn't make sense to make the Bridge a singleton (what if you had multiple web views in your application, for example?).
Here's an SSCCE:
package application;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class WebViewTest extends Application {
#Override
public void start(Stage primaryStage) {
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
Label output = new Label();
Bridge bridge = new Bridge(engine);
engine.load(getClass().getResource("/resources/First.html").toExternalForm());
Button first = new Button("Load First");
first.setOnAction(e -> engine.load(getClass().getResource("/resources/First.html").toExternalForm()));
Button second = new Button("Load Second");
second.setOnAction(e -> engine.load(getClass().getResource("/resources/Second.html").toExternalForm()));
TextField textField = new TextField();
Button button = new Button("Send");
EventHandler<ActionEvent> handler = e -> {
bridge.execute(result -> output.setText(result.toString()),
"showText", textField.getText());
textField.setText("");
};
button.setOnAction(handler);
textField.setOnAction(handler);
HBox controls = new HBox(5, first, second, textField, button, new Label("Web page says: "), output);
controls.setPadding(new Insets(10));
BorderPane root = new BorderPane(webView, null, null, controls, null);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The Bridge class:
package application;
import java.util.function.Consumer;
import javafx.concurrent.Worker.State;
import javafx.scene.web.WebEngine;
import netscape.javascript.JSObject;
public class Bridge {
private JSObject window ;
public Bridge(WebEngine engine) {
engine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
if (newState == State.SUCCEEDED) {
window = (JSObject) engine.executeScript("window");
window.setMember("application", this);
}
});
}
public void execute(Consumer<Object> callback, String function, Object... args) {
callback.accept(window.call(function, args));
}
}
And some simple test HTML files, which I have in a resources folder in the root of the classpath.
First.HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>First</title>
<script>
function showText(text) {
document.getElementById("text").innerHTML = text;
return text;
}
</script>
</head>
<body>
<p>This is the first page</p>
Go to the second page
<div id="text"></div>
</body>
</html>
and Second.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Second</title>
<script>
function showText(text) {
document.getElementById("text").innerHTML = text;
return text;
}
</script>
</head>
<body>
<p>This is the second page</p>
Go back to the first page
<div id="text"></div>
</body>
</html>
I want to dynamically load and interact with SVG image into Android WebView using javascript and HTML5. The below is the html source code
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="obj_idset.js"></script>
<script type="text/javascript" src="global.js"></script>
<script type="text/javascript" src="map_zoom_pan_effects.js"></script>
<script type="text/javascript" src="client-menu_position.js"></script>
<script type="text/javascript" src="client-menu_routing.js"></script>
<script type="text/javascript" src="obj_positionpoint.js"></script>
<script type="text/javascript" src="obj_borderline.js"></script>
<script type="text/javascript" src="obj_borderpoint.js"></script>
<script type="text/javascript" src="obj_edge.js"></script>
<script type="text/javascript" src="obj_polygon.js"></script>
<script type="text/javascript" src="obj_stepmarker.js"></script>
<script type="text/javascript" src="obj_vertex.js"></script>
<script type="text/javascript" src="obj_category.js"></script>
<script type="text/javascript" src="obj_gpsmarker.js"></script>
<script type="text/javascript" src="menu_import.js"></script>
<script type="text/javascript" src="routing.js"></script>
<script type="text/javascript" src="affiliation_match.js"></script>
<script type="text/javascript" src="android.js"></script>
<script type="text/javascript" src="interface.js"></script>
<script type="text/javascript" src="demowalk.js"></script>
<script type="text/javascript" src="convertCoordinates.js"></script>
<script>
$("embed").ready(function() {
// Replaces onload () for initialization may take place only after the DOM has been built completely.
console.log('version 24');
//G.loadMaps(false);
G.init();
G.loadMaps(0);
console.log("???");
});
</script>
</head>
<body>
<div id="location"></div>
<!-- Inside this div the map will be rendered -->
<div id="map_container"></div>
<!-- <div id="page-wrapper">
<h1>Text File Reader</h1>
<div>
Select a text file:
<input type="file" id="fileInput">
</div>
<pre id="fileDisplayArea"><pre>
</div>
-->
<div id="mainmenu">
<p>Set the position</p>
<!-- <button onclick="menu('top');">top</button> -->
<button onclick="Interface.position_setSVG (125,125,0);">Set postion</button>
</div>
</body>
</html>
As above html script, the html web page includes a render SVG map which is dynamically load into element and a "Set position" button as below in desktop Chrome.
Now I want to display the same in Android WebView (all java script files and svg files are placed in Android assests folder). The below is Android code in main Fragment
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
private SvgWebView mWebView;
private Button positionBtn;
private Button destinationBtn;
private Button routingBtn;
private Button clearBtn;
public PlaceholderFragment() {
}
#Override
#SuppressLint({ "JavascriptInterface", "SetJavaScriptEnabled" })
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
mWebView = new SvgWebView((WebView) rootView.findViewById(R.id.webView1));
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setBuiltInZoomControls(false);
mWebView.getSettings().setUseWideViewPort(true);
mWebView.getSettings().setSupportZoom(true);
mWebView.getWebView().setInitialScale(0);
mWebView.getWebView().setWebChromeClient(new WebChromeClient());
// http://stackoverflow.com/questions/2378800/clicking-urls-opens-default-browser
mWebView.getWebView().setWebViewClient(new WebViewClient(){
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
CustomJavaScriptHandler js = new CustomJavaScriptHandler(getActivity());
mWebView.getWebView().addJavascriptInterface(js, "svgapp");
js.addInstructor(new CustomJavaScriptHandler.JSInstructor() {
#Override
public void jsinstruct(String s) {
String parts[] = s.split(":");
if (parts[0].equals("position")) {
//nodeSelected(Integer.valueOf(parts[1]));
}
}
});
CopyFilesAsyncTask copyTask = new CopyFilesAsyncTask();
copyTask.execute();
positionBtn = (Button) rootView.findViewById(R.id.positionBtn);
positionBtn.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
mWebView.svgPositionBySvg(100.0, 200.0, 0);
}
});
destinationBtn = (Button) rootView.findViewById(R.id.destinationBtn);
routingBtn = (Button) rootView.findViewById(R.id.routingBtn);
clearBtn = (Button) rootView.findViewById(R.id.clearBtn);
return rootView;
}
/* the function is called after copying files from assest folder to external device */
public void copyFinished() {
try {
Toast.makeText(getActivity(), "Copy done", Toast.LENGTH_LONG).show();
String htmlPath = Utils.getSdDir(Utils.SVG_MAP_DATA_EXT_FOLDER).toURI().toURL().toString() + File.separator + Utils.ANDROID_HTML;
// load the android.html
mWebView.loadUrl(htmlPath);
} catch (MalformedURLException e) {
Log.e(TAG, "Error ", e);
}
}
class CopyFilesAsyncTask extends AsyncTask<Void, Void, Void> {
public CopyFilesAsyncTask() {
}
#Override
protected Void doInBackground(Void... arg0) {
AssetManager assetManager = getActivity().getAssets();
copyAssestsToExtDir(assetManager, Utils.SVG_MAP_DATA_ASSEST_FOLDER);
return null;
}
#Override
protected void onPostExecute(Void arg0) {
copyFinished();
}
}
/* copy files in assest to external dir when the application start */
private void copyAssestsToExtDir(AssetManager assetManager, String subfolder) {
String[] files = null;
try {
files = assetManager.list(subfolder);
} catch (IOException e) {
Log.e(TAG, "Failed to get asset file list.", e);
}
for(String filename : files) {
Log.i(TAG, "File: " + filename);
// this is file, hence copy
InputStream instr = null;
OutputStream outstr = null;
try {
instr = assetManager.open(subfolder + File.separator + filename);
File out_dir = Utils.getSdDir(Utils.SVG_MAP_DATA_EXT_FOLDER);
File outFile = new File(out_dir, filename);
outstr = new FileOutputStream(outFile);
byte[] buffer = new byte[1024];
int read;
while ((read = instr.read(buffer)) != -1) {
outstr.write(buffer, 0, read);
}
outstr.flush();
instr.close();
outstr.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
The thing is that when running in Android, the WebView does not load svg image into its element. It calls default Android Web Browser to display the svg image as below pictures
As above pictures, the WebView only display the "Set postion" button, it call Android web Browser to display SVG. Hence, I could not interact with loaded SVG because SVG does not include any javascript itself (javascript files are embeded into html file not svg).
Am I missing something? Could anyone give me the solution to solve this problem?
The problem is Android 4.4 KitKat.
If the above application run on 4.2 or below, it works well. But if running in 4.4, Android will call Android browser to display the embed svg image.
Due to some security feature, KitKat does not allow to load file stored in internal device. You must place the file on a external server.
I'm trying to start an activity from a javascript interface in my webview.
The example shows a toast. How could i call a class instead of a toast?
public class JavaScriptInterface {
Context mContext;
/** Instantiate the interface and set the context */
JavaScriptInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
this for the html page.
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
You have to first register the JavaScriptInterface on your webview.
JavaScriptInterFace can be a inner class as shown below. This class will have a function that you can call from html page( via javaScript ) and inside this function you can write code to change activity.
Here is the working solution for you:
public class JavascriptInterfaceActivity extends Activity {
/** Called when the activity is first created. */
WebView wv;
JavaScriptInterface JSInterface;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
wv = (WebView)findViewById(R.id.webView1);
wv.getSettings().setJavaScriptEnabled(true);
// register class containing methods to be exposed to JavaScript
JSInterface = new JavaScriptInterface(this);
wv.addJavascriptInterface(JSInterface, "JSInterface");
wv.loadUrl("file:///android_asset/myPage.html");
}
public class JavaScriptInterface {
Context mContext;
/** Instantiate the interface and set the context */
JavaScriptInterface(Context c) {
mContext = c;
}
#android.webkit.JavascriptInterface
public void changeActivity()
{
Intent i = new Intent(JavascriptInterfaceActivity.this, nextActivity.class);
startActivity(i);
finish();
}
}
}
Here is the html page
<html>
<head>
<script type="text/javascript">
function displaymessage()
{
JSInterface.changeActivity();
}
</script>
</head>
<body>
<form>
<input type="button" value="Click me!" onclick="displaymessage()" />
</form>
</body>
</html>
Hope this helps...
You also need to add the #android.webkit.JavascriptInterface annotation on top of your changeActivity method in your android code, should you run on Android 4.2 or higher.
See this link for more.
This is the entire Java code I've used. I will explain in more detail below...
public class Test7 extends Activity {
//debug
private final static String TAG = "JSInterface";
private WebView wv;
private class JSInterface {
private WebView wv;
// Variables to manage interfacing with JS
private String returnValue;
private boolean canReadReturnValue;
private Lock lockOnJS;
private Condition condVarOnJS;
public JSInterface (WebView wv) {
this.wv = wv;
this.canReadReturnValue = false;
this.lockOnJS = new ReentrantLock();
this.condVarOnJS = lockOnJS.newCondition();
}
public void setReturnValue(String ret) {
lockOnJS.lock();
returnValue = ret;
canReadReturnValue = true;
condVarOnJS.signal();
lockOnJS.unlock();
Log.d(TAG, "returnValue = " + returnValue);
}
public String getReturnValue() {
Log.d(TAG, "enter in getReturnValue");
lockOnJS.lock();
while (!canReadReturnValue) {
try {
Log.d(TAG, "get wait...");
condVarOnJS.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lockOnJS.unlock();
Log.d(TAG, "returnValue: " + returnValue);
return returnValue;
}
public String getNewString() {
wv.loadUrl("javascript:JSInterface.setReturnValue(createNewString())");
return getReturnValue();
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
wv = (WebView) findViewById(R.id.webView1);
wv.getSettings().setJavaScriptEnabled(true);
wv.addJavascriptInterface(new JSInterface(wv), "JSInterface");
wv.loadUrl("file:///android_asset/prova7.html");
}
public void button1(View v) {
wv.loadUrl("javascript:func('1')");
}
}
And it seems work fine.
You can see that I've got a button (that we can call button1), and clicking on it, it tries to execute a JS method, called func().
public void button1(View v) {
wv.loadUrl("javascript:func('1')");
}
Inside this JS method, I have to call another Java method. This is the code:
function func(id) {
document.getElementById(id).innerHTML = JSInterface.getNewString();
}
I need to return the result of JSInterface.getNewString() to the innerHTML variable.
The code of JSInterface.getNewString() is this:
public String getNewString() {
wv.loadUrl("javascript:JSInterface.setReturnValue(createNewString())");
return getReturnValue();
}
You can see that I use the method setReturnValue and getReturnValue to return the value returned by another JS method. This is the code:
function createNewString() {
return "my New String";
}
The problem is that when I try to set the returnValue, the function createNewString is never executed! If I add a console.log() line, my logCat display nothing!
I cannot understand why this happens.
All the javascript and your JSInterface methods called from javascript are running on the single thread in Android WebView. So while you are waiting in condVarOnJS.await() no javascript can be executed, just because it is executed on the same thread.
Moreover, all the webview instances in your application share the same javascript thread.
In Internet Explorer I found the same problem. You can use setTimeout like this:
function func(id) {
setTimeout(
function(){
document.getElementById(id).innerHTML = JSInterface.getNewString();
},
500);
}
I did the functionality what you intend in that code,for me createNewString() is called,
I will show up the code i used,
In java
,
public String videoPlay(){
System.out.println("videoPlay");
mWebView.loadUrl("javascript:window.demo.setReturnValue(createNewString())");
return getReturnValue();}
public void setReturnValue(String test){
rotValue=test;
System.out.println(test);
}
public String getReturnValue(){
System.out.println("get"+rotValue);
return rotValue;
}
in HTML,
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script>
function inform(){
alert('et');
document.getElementById('myText').value=window.demo.videoPlay();
alert('et');
}
function createNewString() {
return "my New String";
}
</script>
</head>
<body onload="init()">
<form>
<input type='text' id='myText' />
<input type="button" name="test" value="Click me" onclick="inform()">
</form>
</body>
</html>
The function getter and setter called and values also set, but i have the output log as..
11-08 19:18:17.155: INFO/System.out(847): videoPlay
11-08 19:18:17.165: INFO/System.out(847): getnull
11-08 19:18:17.875: INFO/System.out(847): my New String
videoPlay called from JS and createnewString() also called from java to JS , but it returns the value before it set , because i don`t what is the purpose to use lock , even i tried using lock as you did for that it will print
11-08 19:18:17.155: INFO/System.out(847): videoPlay
11-08 19:18:17.165: INFO/System.out(847): getnull
using lock also the function callback works in wrong manner, you need work on locks.