i am try to connect to glassFish-server4.1.1 from my android application
but give me Error failed to connect to /localhost (port 8080) after 90000ms
i change port on server but give me same error
......
it connect to server only on netbeans but on android give me faild and below my code
server code `
#ServerEndpoint("/echo")
public class WebSocketClass {
/**
* #param session
* #OnOpen allows us to intercept the creation of a new session.
* The session class allows us to send data to the user.
* In the method onOpen, we'll let the user know that the handshake was
* successful.
*/
#OnOpen
public void onOpen(Session session){
System.out.println(session.getId() + " has opened a connection");
try {
session.getBasicRemote().sendText("Connection Established");
} catch (IOException ex) {
}
}
/**
* When a user sends a message to the server, this method will intercept the message
* and allow us to react to it. For now the message is read as a String.
* #param message
* #param session
*/
#OnMessage
public void onMessage12(String message, Session session){
System.out.println("Message from " + session.getId() + ": " + message);
try {
session.getBasicRemote().sendText(message);
} catch (IOException ex) {
}
}
/**
* The user closes the connection.
*
* Note: you can't send messages to the client from this method
* #param session
*/
#OnClose
public void onClose(Session session){
System.out.println("Session " +session.getId()+" has ended");
}}
client code
private void connectWebSocket() {
URI uri;
try {
uri = new URI("ws://localhost:8080/WebApplication1/echo");
} catch (URISyntaxException e) {
e.printStackTrace();
return;
}
mWebSocketClient = new WebSocketClient(uri) {
#Override
public void onOpen(ServerHandshake serverHandshake) {
Log.i("Websocket", "Opened");
mWebSocketClient.send("Hello from " + Build.MANUFACTURER + " " + Build.MODEL);
}
#Override
public void onMessage(String s) {
final String message = s;
runOnUiThread(new Runnable() {
#Override
public void run() {
TextView textView = (TextView)findViewById(R.id.messages);
textView.setText(textView.getText() + "\n" + message);
}
});
}
#Override
public void onClose(int i, String s, boolean b) {
Log.i("Websocket", "Closed " + s);
}
#Override
public void onError(Exception e) {
Log.i("Websocket", "Error " + e.getMessage());
}
};
mWebSocketClient.connect();
}
i do't know why this error?
can any one help me...
Maybe you should change the IP to reflect the IP where glassfish server is installed on the client
Related
I m implementing WebSocket messages command-line client.
I have checked that this error corresponds to the problem with the protocol. I upgraded ws to the newest 7.4.1. At backend I use Spring Boot Websockets at version 2.3.4.RELEASE.
The 2 main causes of this are said to be packet loss or malformed messages.
I have made some checks to check those but none seem valid.
The messages I test are small so it shouldn't be the case with message size. The connection is fully on localhost.
I test the solution with 3 users and sometimes I get this error sometimes not.
Can someone help me figure out how to get rid of this type of error?
Here is the code I use for client to send messages:
async function test(number_of_messages, break_between_messages) {
const websocket = new WebSocket(url...)
websocket.on('message', function incoming(data) {
console.log(getMessage("Received", data))
});
websocket.on('close', function(data) {
console.log('Disconnected!!!! ' + data.toString());
});
const opened = await connection(websocket)
//Wait 5 seconds
await sleep(5_000);
if (opened) {
for (i = 0; i < number_of_messages; i++) {
for (const chatId of chatIds) {
let content = i.toString() + " from " + user;
let msg = JSON.stringify({
"chatId": chatId,
"author": user,
"content": content
})
websocket.send(msg)
let message = getMessage("Sent", msg)
console.log(message)
}
await sleep(break_between_messages);
}
} else {
console.log("ERROR on Opening Connection")
return
}
// Wait 1 minute
await sleep(60_000);
websocket.close()
}
With backend code:
#Component
#ServerEndpoint(value = "/webSocket/{username}",
encoders = MessageRepresentationEncoder.class, decoders = MessageRepresentationDecoder.class)
public class MessagingSocket {
private Logger logger = LoggerFactory.getInstance();
private Session session;
private MessagingAPI messagingAPI = MessagingAPIFactory.createAPI();
private UserSocketRegistry userSocketRegistry = UserSocketRegistry.createRegistry();
private SessionUserRegistry sessionUserRegistry = SessionUserRegistry.createRegistry();
#OnOpen
public void onOpen(Session session, #PathParam("username") String username) {
this.session = session;
logger.log(LoggingType.INFO, "Started new session " + session.getId());
logger.log(LoggingType.INFO, username + " connected");
userSocketRegistry.addSessionForUser(this, username);
sessionUserRegistry.addSessionForUser(session, username);
}
#OnMessage //Allows the client to send message to the socket.
public void onMessage(MessageRepresentation messageRepresentation) {
logger.log(LoggingType.INFO, "Received " + messageRepresentation.toString());
messagingAPI.write(WriteMessage.from(UUID.fromString(messageRepresentation.chatId), messageRepresentation.author, messageRepresentation.content));
broadcastToChat(messageRepresentation);
}
private void broadcastToChat(MessageRepresentation message) {
final List<MessagingSocket> sockets = messagingAPI.getUsersConnectedToChat(UUID.fromString(message.chatId)).stream().filter(user -> userSocketRegistry.hasSocketFor(user.getName()))
.map(user -> userSocketRegistry.getSocketFor(user.getName())).collect(Collectors.toList());
logger.log(LoggingType.INFO, "Starting broadcast of " + message.content + " from " + message.author + " for " + String.join(",", messagingAPI.getUsersConnectedToChat(UUID.fromString(message.chatId)).stream().map(x -> x.getName()).collect(Collectors.toList())));
for (MessagingSocket messagingSocket : sockets) {
logger.log(LoggingType.INFO, "Broadcasting message" + message.content + " to " + messagingSocket.session.getId());
messagingSocket.sendMessage(message);
}
}
private void sendMessage(MessageRepresentation message) {
try {
this.session.getBasicRemote().sendObject(message);
} catch (IOException | EncodeException e) {
logger.log(LoggingType.ERROR, "Caught exception while sending message to Session Id: " + this.session.getId());
}
}
#OnClose
public void onClose(Session session) {
String user = sessionUserRegistry.getUserFor(session);
logger.log(LoggingType.INFO, "User " + user + " with session " + this.session.getId() + " disconnected ");
sessionUserRegistry.removeSession(session);
userSocketRegistry.removeUser(user);
}
}
And MessageRepresentation as:
public class MessageRepresentation {
public String chatId;
public String author;
public String content;
#Override
public String toString() {
return "MessageRepresentation{" +
"chatId='" + chatId + '\'' +
", author='" + author + '\'' +
", content='" + content + '\'' +
'}';
}
}
After further investigation I m getting the following exception:
java.lang.IllegalStateException: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.checkState(WsRemoteEndpointImplBase.java:1243)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.textStart(WsRemoteEndpointImplBase.java:1205)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendString(WsRemoteEndpointImplBase.java:191)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendObject(WsRemoteEndpointImplBase.java:600)
at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendObject(WsRemoteEndpointBasic.java:74)
at presentation.frontend.websockets.server.MessagingSocket.sendMessage(MessagingSocket.java:64)
at presentation.frontend.websockets.server.MessagingSocket.broadcastToChat(MessagingSocket.java:57)
at presentation.frontend.websockets.server.MessagingSocket.onMessage(MessagingSocket.java:47)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBase.onMessage(PojoMessageHandlerWholeBase.java:80)
at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:402)
at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageText(WsFrameServer.java:119)
at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:502)
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:301)
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:133)
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:82)
at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:171)
at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:151)
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148)
at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:59)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
java.lang.IllegalStateException: Message will not be sent because the WebSocket session has been closed
I could be off the mark here but I think this is probably due to the message containing invalid UTF8 or some such. i.e. malformed.
If this sounds like it could be the cause the simple fix would be to encode the msg
let msg = JSON.stringify({
"chatId": chatId,
"author": user,
"content": content
})
to
let msg = unescape(encodeURIComponent(JSON.stringify({
"chatId": chatId,
"author": user,
"content": content
})));
Then decode on the other side...
JSON.parse(decodeURIComponent(escape( ... )))
The solution to this one involved 2 steps.
1: Find the error stacktrace
#OnError
public void onError(Session session, Throwable throwable) {
logger.log(LoggingType.ERROR, "Error for " + session.getId() + " caused by: " + throwable.getMessage());
throwable.printStackTrace();
}
2: Change synchronous BasicRemote to asynchronous AsyncRemote in broadcasting messages (this is important when the number of messages increased)
private void sendMessage(MessageRepresentation message) {
this.session.getAsyncRemote().sendObject(message);
}
I am trying to figure out a way to use Node as a client that would send out data to a server listening on an Android app. The android app will initially send a post request to the Node server with its public IP address and the port it will be listening on (socket). Once there is anything new, the Node server would then send a packet of JSON data onto that particular app via the registered socket.
Is this possible in Node, and if not how can I implement it in Javascript, or what is the best way to implement this?
Here is the Android app server
public class AndroidAppLocalServer {
Activity activity;
ServerSocket serverSocket;
String message = "";
static final int socketServerPORT = 8080;
public AndroidAppLocalServer(Activity activity) {
this.activity = activity;
Thread socketServerThread = new Thread(new SocketServerThread());
socketServerThread.start();
}
public int getPort() {
return socketServerPORT;
}
public void onDestroy() {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerThread extends Thread {
int count = 0;
#Override
public void run() {
try {
// create ServerSocket using specified port
serverSocket = new ServerSocket(socketServerPORT);
while (true) {
// block the call until connection is created and return
// Socket object
Socket socket = serverSocket.accept();
count++;
message += "#" + count + " from "
+ socket.getInetAddress() + ":"
+ socket.getPort() + "\n";
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("MyApp", message);
}
});
SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread(socket, count);
socketServerReplyThread.run();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerReplyThread extends Thread {
private Socket hostThreadSocket;
int cnt;
SocketServerReplyThread(Socket socket, int c) {
hostThreadSocket = socket;
cnt = c;
}
#Override
public void run() {
OutputStream outputStream;
String msgReply = "Hello from AndroidAppLocalServer, you are #" + cnt;
try {
outputStream = hostThreadSocket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.print(msgReply);
printStream.close();
message += "replayed: " + msgReply + "\n";
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("MyApp", message);
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
message += "Something wrong! " + e.toString() + "\n";
}
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("MyApp", message);
}
});
}
}
public String getIpAddress() {
String ip = "";
try {
Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface.getNetworkInterfaces();
while (enumNetworkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = enumNetworkInterfaces.nextElement();
Enumeration<InetAddress> enumInetAddress = networkInterface.getInetAddresses();
while (enumInetAddress.hasMoreElements()) {
InetAddress inetAddress = enumInetAddress.nextElement();
if (inetAddress.isSiteLocalAddress()) {
ip += "AndroidAppLocalServer running at : " + inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ip += "Something Wrong! " + e.toString() + "\n";
}
return ip;
}
}
Yes you can do this in Node.js, assuming that the App runs on a phone that is actually publicly reachable. Since you are using a plain TCP socket in your Android application, you can verify first by manually connecting the socket by using a tool such as netcat or telnet (e.g., netcat <PUBLIC-IP> 8080).
If this works you can do the same thing from within Node.js by using the net.Socket class.
const net = require('net');
const client = new net.Socket();
client.connect(8080, '<PUBLIC-IP>', () => {
// callback, when connection successfull
client.write('Data sent to the App');
});
client.on('data', (data) => {
// callback, when app replies with data
});
client.on('close', (data) => {
// callback, when socket is closed
});
However, depending on what you actually try to achieve, you might want check out how Android applications usually implement push notifications.
I am trying to establish a connection between android app and webservice. I am sending the encrypted username and password using AES encryption. But my encrypted username and password do not match with the webservice and responses as false.
Same thing I am doing in website encrypting credential with AES encryption in javascript and validating user with webservice everything works fine. I checked AES output for android defers from javascript output.
Bellow code is used in android to encrypt username and password
public class RijndaelCrypt {
public static final String TAG = "EncryptLog2";
private static String TRANSFORMATION = "AES/CBC/PKCS7Padding";
private static String ALGORITHM = "AES";
private static String DIGEST = "MD5";
private static Cipher _cipher;
private static SecretKey skeySpec;
private static IvParameterSpec _IVParamSpec;
//16-byte private key
private static byte[] IV = MainActivity.key.substring(0,16).getBytes();
/**
* Constructor
*
* #password Public key
*/
public RijndaelCrypt(String password) {
try {
//Encode digest
MessageDigest digest;
digest = MessageDigest.getInstance(DIGEST);
skeySpec = new SecretKeySpec(digest.digest(password.getBytes()), ALGORITHM);
//Initialize objects
_cipher = Cipher.getInstance(TRANSFORMATION);
_IVParamSpec = new IvParameterSpec(IV);
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "No such algorithm " + ALGORITHM, e);
} catch (NoSuchPaddingException e) {
Log.e(TAG, "No such padding PKCS7", e);
}
}
/**
* Encryptor.
*
* #return Base64 encrypted text
* #text String to be encrypted
*/
public String encrypt(byte[] text) {
byte[] encryptedData;
try {
_cipher.init(Cipher.ENCRYPT_MODE, skeySpec, _IVParamSpec);
encryptedData = _cipher.doFinal(text);
} catch (InvalidKeyException e) {
Log.e(TAG, "Invalid key (invalid encoding, wrong length, uninitialized, etc).", e);
return null;
} catch (InvalidAlgorithmParameterException e) {
Log.e(TAG, "Invalid or inappropriate algorithm parameters for " + ALGORITHM, e);
return null;
} catch (IllegalBlockSizeException e) {
Log.e(TAG, "The length of data provided to a block cipher is incorrect", e);
return null;
} catch (BadPaddingException e) {
Log.e(TAG, "The input data but the data is not padded properly.", e);
return null;
}
return Base64.encodeToString(encryptedData, Base64.DEFAULT);
}
/**
* Decryptor.
*
* #return decrypted text
* #text Base64 string to be decrypted
*/
public String decrypt(String text) {
try {
_cipher.init(Cipher.DECRYPT_MODE, skeySpec, _IVParamSpec);
byte[] decodedValue = Base64.decode(text.getBytes(), Base64.DEFAULT);
byte[] decryptedVal = _cipher.doFinal(decodedValue);
return new String(decryptedVal);
} catch (InvalidKeyException e) {
Log.e(TAG, "Invalid key (invalid encoding, wrong length, uninitialized, etc).", e);
return null;
} catch (InvalidAlgorithmParameterException e) {
Log.e(TAG, "Invalid or inappropriate algorithm parameters for " + ALGORITHM, e);
return null;
} catch (IllegalBlockSizeException e) {
Log.e(TAG, "The length of data provided to a block cipher is incorrect", e);
return null;
} catch (BadPaddingException e) {
Log.e(TAG, "The input data but the data is not padded properly.", e);
return null;
}
}
}
Can i use that javascript in android without WebView.
Note: webservice is built in .net c#.
Sorry for any grammatical mistake, This is my 1st question on StackOverflow.
Is there a way to make Phonegap's File API work just like same API works in browser?
I need same behavior as in browser: Tap on "Open file" button -> "Select File" dialog ->... -> Opening the file with FileReader Object.
Thank you!!!
UPDATE: I've found some solution. It opens File Dialog and it returns the name of the JS File Object. But when i pass that JS File Object to FileReader from PhoneGap - it doesn't open (onload listener never fires). What i do wrong?
Here's my Java:
package org.apache.cordova.example;
import android.os.Bundle;
import org.apache.cordova.api.CordovaInterface;
import android.content.Intent;
import android.net.Uri;
import android.webkit.ValueCallback;
import org.apache.cordova.CordovaChromeClient;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.DroidGap;
public class cordovaExample extends DroidGap
{
private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE = 1;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html");
this.appView.setWebChromeClient(new FileAttachmentChromeClient(this, this.appView));
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage) return;
Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
// openFileChooser is an overridable method in WebChromeClient which isn't
// included in the SDK's Android stub code
public class FileAttachmentChromeClient extends CordovaChromeClient {
public FileAttachmentChromeClient(CordovaInterface ctx, CordovaWebView app) {
super(ctx, app);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
cordovaExample.this.startActivityForResult(Intent.createChooser(i, "Choose type of attachment"), FILECHOOSER_RESULTCODE);
}
}
}
And what i do with JavaScript:
var SelectedFile;
var FReader;
document.getElementById('fileBox').addEventListener('change', fileChosen);
function fileChosen(evnt) {
SelectedFile = evnt.target.files[0];
FReader = new FileReader();
FReader.readAsDataURL(SelectedFile);
FReader.onload = function(loadevnt){ .... } //never happens
}
Well the problem is most mobile browsers do not support the file dialog. IIRC iOS 6 is the first mobile browser to support this functionality. I did write some code in my Corinthian project, not under active development, that does monkey patch this functionality.
First you'd need to write an Android plugin to start an intent to provide the file dialog. I'm using OI File Manager.
package org.apache.cordova;
import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;
import org.apache.cordova.api.LOG;
import org.apache.cordova.api.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
/**
* This class exposes methods in DroidGap that can be called from JavaScript.
*/
public class App extends CordovaPlugin {
/**
* Executes the request and returns PluginResult.
*
* #param action The action to execute.
* #param args JSONArry of arguments for the plugin.
* #param callbackContext The callback context from which we were invoked.
* #return A PluginResult object with a status and message.
*/
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
try {
if (action.equals("clearCache")) {
this.clearCache();
}
else if (action.equals("show")) {
// This gets called from JavaScript onCordovaReady to show the webview.
// I recommend we change the name of the Message as spinner/stop is not
// indicative of what this actually does (shows the webview).
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
webView.postMessage("spinner", "stop");
}
});
}
else if (action.equals("loadUrl")) {
this.loadUrl(args.getString(0), args.optJSONObject(1));
}
else if (action.equals("cancelLoadUrl")) {
this.cancelLoadUrl();
}
else if (action.equals("clearHistory")) {
this.clearHistory();
}
else if (action.equals("backHistory")) {
this.backHistory();
}
else if (action.equals("overrideButton")) {
this.overrideButton(args.getString(0), args.getBoolean(1));
}
else if (action.equals("overrideBackbutton")) {
this.overrideBackbutton(args.getBoolean(0));
}
else if (action.equals("exitApp")) {
this.exitApp();
}
callbackContext.sendPluginResult(new PluginResult(status, result));
return true;
} catch (JSONException e) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
return false;
}
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
/**
* Clear the resource cache.
*/
public void clearCache() {
this.webView.clearCache(true);
}
/**
* Load the url into the webview.
*
* #param url
* #param props Properties that can be passed in to the DroidGap activity (i.e. loadingDialog, wait, ...)
* #throws JSONException
*/
public void loadUrl(String url, JSONObject props) throws JSONException {
LOG.d("App", "App.loadUrl("+url+","+props+")");
int wait = 0;
boolean openExternal = false;
boolean clearHistory = false;
// If there are properties, then set them on the Activity
HashMap<String, Object> params = new HashMap<String, Object>();
if (props != null) {
JSONArray keys = props.names();
for (int i = 0; i < keys.length(); i++) {
String key = keys.getString(i);
if (key.equals("wait")) {
wait = props.getInt(key);
}
else if (key.equalsIgnoreCase("openexternal")) {
openExternal = props.getBoolean(key);
}
else if (key.equalsIgnoreCase("clearhistory")) {
clearHistory = props.getBoolean(key);
}
else {
Object value = props.get(key);
if (value == null) {
}
else if (value.getClass().equals(String.class)) {
params.put(key, (String)value);
}
else if (value.getClass().equals(Boolean.class)) {
params.put(key, (Boolean)value);
}
else if (value.getClass().equals(Integer.class)) {
params.put(key, (Integer)value);
}
}
}
}
// If wait property, then delay loading
if (wait > 0) {
try {
synchronized(this) {
this.wait(wait);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.webView.showWebPage(url, openExternal, clearHistory, params);
}
/**
* Cancel loadUrl before it has been loaded (Only works on a CordovaInterface class)
*/
#Deprecated
public void cancelLoadUrl() {
this.cordova.cancelLoadUrl();
}
/**
* Clear page history for the app.
*/
public void clearHistory() {
this.webView.clearHistory();
}
/**
* Go to previous page displayed.
* This is the same as pressing the backbutton on Android device.
*/
public void backHistory() {
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
webView.backHistory();
}
});
}
/**
* Override the default behavior of the Android back button.
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
*
* #param override T=override, F=cancel override
*/
public void overrideBackbutton(boolean override) {
LOG.i("App", "WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!");
webView.bindButton(override);
}
/**
* Override the default behavior of the Android volume buttons.
* If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired.
*
* #param button volumeup, volumedown
* #param override T=override, F=cancel override
*/
public void overrideButton(String button, boolean override) {
LOG.i("DroidGap", "WARNING: Volume Button Default Behaviour will be overridden. The volume event will be fired!");
webView.bindButton(button, override);
}
/**
* Return whether the Android back button is overridden by the user.
*
* #return boolean
*/
public boolean isBackbuttonOverridden() {
return webView.isBackButtonBound();
}
/**
* Exit the Android application.
*/
public void exitApp() {
this.webView.postMessage("exit", null);
}
}
package com.simonmacdonald.corinthian;
import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult;
import org.json.JSONArray;
import org.json.JSONObject;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
public class FileDialog extends Plugin {
private static final int PICK_FILE_RESULT_CODE = 8974;
private static final int PICK_DIRECTORY_RESULT_CODE = 8975;
private static final String LOG_TAG = "FileDialog";
public String callbackId;
/**
* Executes the request and returns PluginResult.
*
* #param action The action to execute.
* #param args JSONArry of arguments for the plugin.
* #param callbackId The callback id used when calling back into JavaScript.
* #return A PluginResult object with a status and message.
*/
#Override
public PluginResult execute(String action, JSONArray args, String callbackId) {
this.callbackId = callbackId;
JSONObject options = args.optJSONObject(0);
if (action.equals("pickFile")) {
showDialog(options, PICK_FILE_RESULT_CODE);
} else if (action.equals("pickFolder")) {
showDialog(options, PICK_DIRECTORY_RESULT_CODE);
}
else {
return new PluginResult(PluginResult.Status.INVALID_ACTION);
}
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true);
return r;
}
private void showDialog(JSONObject options, int type) {
Intent intent;
if (type == PICK_FILE_RESULT_CODE) {
intent = new Intent("org.openintents.action.PICK_FILE");
} else {
intent = new Intent("org.openintents.action.PICK_DIRECTORY");
}
if (options != null) {
String title = options.optString("title");
if (title != null) {
intent.putExtra("org.openintents.extra.TITLE", title);
}
String button = options.optString("button");
if (button != null) {
intent.putExtra("org.openintents.extra.BUTTON_TEXT", button);
}
}
//intent.setData(Uri.fromFile(new File("/")));
try {
this.cordova.startActivityForResult((Plugin)this,intent,PICK_FILE_RESULT_CODE);
} catch (ActivityNotFoundException e) {
showDownloadDialog();
}
}
private void showDownloadDialog() {
final Context context = this.cordova.getContext();
Runnable runnable = new Runnable() {
public void run() {
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle("Install File Manager?");
dialog.setMessage("This requires the free OI File Manager app. Would you like to install it now?");
dialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int i) {
dlg.dismiss();
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("market://search?q=pname:org.openintents.filemanager")
);
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
// We don't have the market app installed, so download it directly.
Intent in = new Intent(Intent.ACTION_VIEW);
in.setData(Uri.parse("http://openintents.googlecode.com/files/FileManager-1.2.apk"));
context.startActivity(in);
}
}
});
dialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int i) {
dlg.dismiss();
}
});
dialog.create();
dialog.show();
}
};
this.cordova.getActivity().runOnUiThread(runnable);
}
#Override
public void onActivityResult(int reqCode, int resultCode, Intent data) {
//super.onActivityResult(reqCode, resultCode, data);
//Log.d(LOG_TAG, "Data is " + data.getData().toString());
Log.d(LOG_TAG, "we are in on activity result");
switch (reqCode) {
case PICK_FILE_RESULT_CODE:
case PICK_DIRECTORY_RESULT_CODE: {
if (resultCode==Activity.RESULT_OK && data!=null && data.getData()!=null) {
String filePath = "file://" + data.getData().getPath();
Log.d(LOG_TAG, "The data is = " + filePath);
Log.d(LOG_TAG, "Calling succes with callback id = " + this.callbackId);
this.success(new PluginResult(PluginResult.Status.OK, filePath), this.callbackId);
}
break;
}
}
}
}
Then you'd need to write your JavaScript interface:
FileDialog: {
pickFile: function(successCallback, errorCallback, options) {
var win = typeof successCallback !== 'function' ? null : function(f) {
window.resolveLocalFileSystemURI(f, function(fileEntry) {
successCallback(fileEntry);
}, fail);
};
cordova.exec(win, errorCallback, "FileDialog", "pickFile", [options]);
},
pickFolder: function(successCallback, errorCallback, options) {
var win = typeof successCallback !== 'function' ? null : function(d) {
window.resolveLocalFileSystemURI(d, function(dirEntry) {
successCallback(dirEntry);
}, fail);
};
cordova.exec(win, errorCallback, "FileDialog", "pickFolder", [options]);
},
patch: function() {
var inputs = document.getElementsByTagName("input");
for (var i=0; i < inputs.length; i++) {
if (inputs[i].getAttribute('type') == 'file'){
var me = inputs[i];
inputs[i].addEventListener("click", function() {
corinthian.FileDialog.pickFile(function(fileEntry) {
me.value = fileEntry.fullPath;
});
});
}
}
}
}
and finally monkey patch by calling FileDialog.patch(); once you have received the deviceready event in PhoneGap.
Hope this helps...
I have a android method which one is called from Javascript for getting the selected filepath info from phone gallery. Now i want to send the filepath name to the javascript method but if i return the filepath name from the android function then it will always return the last filepath info not the current one (May be its for callback!) or if i call any javascript method to send the file info after getting the file path then its show on debug console
like that:
05-04 22:07:50.274: ERROR/Web Console(331): ReferenceError: Can't find variable: SetImageFileName at undefined:1
And here is my Code what i have done...
public class Hello extends Activity {
/** Called when the activity is first created. */
WebView webview;
private ProgressDialog progressBar;
private static final int SELECT_PICTURE = 1;
private static final int PICK_IMAGE = 1;
private String selectedImagePath;
private String filemanagerstring;
private long siteId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webview = (WebView) findViewById(R.id.webview);
webview.addJavascriptInterface(new JavaScriptInterface(this), "Android");
webview.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
webview.setWebViewClient(new HelloWebViewClient());
WebSettings webSettings = webview.getSettings();
webSettings.setSavePassword(false);
webSettings.setSaveFormData(false);
webSettings.setJavaScriptEnabled(true);
webSettings.setSupportZoom(false);
webview.loadUrl(getString(R.string.ApplicationWebURL));
}
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if (cursor != null) {
// HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
// THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else
return null;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
String filePath = null;
try {
// OI FILE Manager
filemanagerstring = selectedImageUri.getPath();
// MEDIA GALLERY
selectedImagePath = getPath(selectedImageUri);
selectedFileName=getFileName(selectedImagePath);
if (selectedImagePath != null) {
filePath = selectedImagePath;
}
else if (filemanagerstring != null) {
filePath = filemanagerstring;
}
else {
Toast.makeText(getApplicationContext(), "Unknown path",
Toast.LENGTH_LONG).show();
Log.e("Bitmap", "Unknown path");
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Internal error",
Toast.LENGTH_LONG).show();
Log.e(e.getClass().getName(), e.getMessage(), e);
}
}
}
}
final class JavaScriptInterface {
Context mContext;
JavaScriptInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
public String ShowPhoneGallery(long sId) {
try {
siteId=sId;
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"),PICK_IMAGE);
} catch (Exception e) {
Toast.makeText(getApplicationContext(),e.getMessage(),Toast.LENGTH_LONG).show();
Log.e(e.getClass().getName(), e.getMessage(), e);
}
//Calling Javascript to return the value
webview.loadUrl("javascript:SetImageFileName('"+ selectedImagePath +"')");
return selectedImagePath;
}
}
}
I
s there anybody who can help me on this issue ...
Looks to me like you need to put this line
webview.loadUrl("javascript:SetImageFileName('"+ selectedImagePath +"')");
in a different method which is then called from onActivityResult once your user has selected the picture