I have an android application in which I have a webview. How can I when I press the back button on android I can delete a character in the text area of webview?
package com.example.nqc.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
public class MainActivity extends AppCompatActivity {
private WebView mWebView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = findViewById(R.id.mWebView);
mWebView.loadUrl("https://www.google.com");
}
#Override
public void onBackPressed() {
//delete a character
Log.d("Debug", "Delete text on TextArea");
}
}
Please see the picture below if you do not understand what I said.
Before press back
After press back
There is no guarantee that there will be only one Form in the page the user has loaded.
However, if it's for the Google Search Form in particular, you can then execute a JavaScript to get a Form in the Google.com page that has id=tsf (which is the unique id of the search form in Google.com).
Nevertheless, you mentioned in your comment:
This will happen to all other pages
Unless you know the id of the form in the page (which is practically impossible for every page in WWW that contains more than one Form).
You can loop through all Forms and remove the last char of the text in the Form's input of type text.
Example
First create a method to run the JS script (note that there are different ways to execute a JS in WebView in Android, for more details in case the following method did not work for you, look here):
public void run(final String script) {
mWebView.post(new Runnable() {
#Override
public void run() {
mWebView.loadUrl("javascript:" + script);
}
});
}
Then create a method that returns a JS String to:
Get all Forms in the page.
Cycle through them all.
Cycle through the elements of each Form..
Set its value to (its old value - last char).
private String deleteLastCharScript() {
return "var listOfForms = document.forms;\n" +
"for(var i = 0; i < listOfForms.length; i++) {\n" +
" var elements = listOfForms[i].elements;\n" +
" for(var j = 0 ; j < elements.length ; j++){\n" +
" var item = elements.item(j);\n" +
" item.value = item.value.substring(0, item.value.length - 1);\n" +
" }\n" +
"};";
}
You can run that script in the onBackPressed() method like this:
#Override
public void onBackPressed() {
run(deleteLastCharScript());
}
This is MCVE:
Add to Manifest:
<uses-permission android:name="android.permission.INTERNET" />
Create Simple WebView Layout:
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/webView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
Implementation in Activity:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
public class MainActivity extends AppCompatActivity {
private WebView mWebView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webview);
mWebView = findViewById(R.id.webView1);
mWebView.getSettings().setJavaScriptEnabled(true); // enable JS
mWebView.loadUrl("https://www.google.com");
}
/**
* Execute JS String Asynchronously
* #param script
*/
public void run(final String script) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
// run JavaScript asynchronously
// it works on KitKat onwards
mWebView.evaluateJavascript(script, null);
}else {
// use different thread to run JavaScript asynchronously
// because evaluateJavascript doesn't work on versions before KitKat
new Thread(new Runnable() {
#Override
public void run() {
mWebView.post(new Runnable() {
#Override
public void run() {
mWebView.loadUrl("javascript:" + script);
}
});
}
}).start();
}
}
/**
* This JS Script tp Loop through all
* inputs in all forms in the page
* and remove last char from each
* #return
*/
private String deleteLastCharScript() {
return "var listOfForms = document.forms;\n" +
"for(var i = 0; i < listOfForms.length; i++) {\n" +
" var elements = listOfForms[i].elements;\n" +
" for(var j = 0 ; j < elements.length ; j++){\n" +
" var item = elements.item(j);\n" +
" item.value = item.value.substring(0, item.value.length - 1);\n" +
" }\n" +
"};";
}
#Override
public void onBackPressed() {
run(deleteLastCharScript());
}
}
Result
Related
I am trying to implement a WebSocket client in Android Studio.
My code works fine but I'd like to clear the text boxes after the data has been set. When I tried to clear my EditText boxes after the 'SEND' button is clicked I found that they were being cleared before they were being used.
If I use the following code the contents of the text boxes gets sent,
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.send);
output = (TextView) findViewById(R.id.output);
client = new OkHttpClient();
add = (EditText) findViewById(R.id.add_str);
cmd = (EditText) findViewById(R.id.cmd_str);
key = (EditText) findViewById(R.id.key_str);
data = (EditText) findViewById(R.id.data_str);
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
start();
}
});
}
But if I use the following...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.send);
output = (TextView) findViewById(R.id.output);
client = new OkHttpClient();
add = (EditText) findViewById(R.id.add_str);
cmd = (EditText) findViewById(R.id.cmd_str);
key = (EditText) findViewById(R.id.key_str);
data = (EditText) findViewById(R.id.data_str);
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
start();
add.getText().clear();
cmd.getText().clear();
key.getText().clear();
data.getText().clear();
}
});
}
I just get an empty string sent. How do I stop this? I have tried setting a sent flag that is only set after the text has been sent...
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
start();
if (sent){
add.getText().clear();
cmd.getText().clear();
key.getText().clear();
data.getText().clear();
sent = false;
}
}
});
...but the text never gets cleared.
Edit #1: Full MainActivity listing
package qdivision.org.websocketexample;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
public class MainActivity extends AppCompatActivity {
private Button start;
private TextView output;
private OkHttpClient client;
public EditText add;
public EditText cmd;
public EditText key;
public EditText data;
public boolean sent = false;
private final class EchoWebSocketListener extends WebSocketListener {
private static final int NORMAL_CLOSURE_STATUS = 1000;
#Override
public void onOpen(WebSocket webSocket, Response response) {
String addStr = add.getText().toString();
String cmdStr = cmd.getText().toString();
String keyStr = key.getText().toString();
String dataStr = data.getText().toString();
String dataFrame = "<" + addStr + "," + cmdStr + "," + keyStr + "," + dataStr + ">";
webSocket.send(dataFrame);
webSocket.close(NORMAL_CLOSURE_STATUS, "Goodbye !");
sent = true;
}
#Override
public void onMessage(WebSocket webSocket, String text) {
output("Receiving : " + text);
}
#Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
output("Receiving bytes : " + bytes.hex());
}
#Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(NORMAL_CLOSURE_STATUS, null);
//output("Closing : " + code + " / " + reason);
}
#Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
output("Error : " + t.getMessage());
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.send);
output = (TextView) findViewById(R.id.output);
client = new OkHttpClient();
add = (EditText) findViewById(R.id.add_str);
cmd = (EditText) findViewById(R.id.cmd_str);
key = (EditText) findViewById(R.id.key_str);
data = (EditText) findViewById(R.id.data_str);
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
start();
/*add.getText().clear();
cmd.getText().clear();
key.getText().clear();
data.getText().clear();*/
}
});
}
private void start() {
Request request = new Request.Builder().url("ws://192.168.1.84:81/").build(); //"ws://echo.websocket.org"
EchoWebSocketListener listener = new EchoWebSocketListener();
WebSocket ws = client.newWebSocket(request, listener);
client.dispatcher().executorService().shutdown();
}
private void output(final String txt) {
runOnUiThread(new Runnable() {
#Override
public void run() {
output.setText(output.getText().toString() + "\n\n" + txt);
}
});
}
}
First of all, about the sent flag. If you are using another thread for settings its value, does not mean, this thread has to wait for it to read the value. In the if statement, if it is not true, it will skip the body. So, as soon as start() is called, assuming that start() is running on another thread, this thread will read the next statement and skip the loop.
Try using something like an OnCompleteListener() provided with the API that you are using.
The same logic goes with the editText.getText().clear(). If you are trying to read the text in start() after any HTTP call, the program will not wait for it and execute the remaining statements.
Hope that helps
Since onOpen happens asynchronously, the values that you're trying to pass are already cleared by that time. The simplest way would be to assign the values from your EditTexts to variables and then read them in onOpen. You could also add a constructor to your Websocket implementation that accepts String as a parameter.
Maybe you can try:
data.setText("");
editText.getText().clear();
will clear the text box.
I'm a newbie android programmer that want to set text from another class
Here is the code:
MainActivity.java
EventHandler eventHandler = new EventHandler();
reader.Events.addEventsListener(eventHandler);
This one another Class but still inside the MainActivity
class EventHandler implements RfidEventsListener {
// Read Event Notification
public void eventReadNotify(RfidReadEvents e){
TagData[] myTags = myReader.Actions.getReadTags(100);
if (myTags != null)
{
for (int index = 0; index < myTags.length; index++)
{
System.out.println("Tag ID " + myTags[index].getTagID());
//I want to settext here
}
}
}
// Status Event Notification
public void eventStatusNotify(RfidStatusEvents e) {
System.out.println("Status Notification: " +
e.StatusEventData.getStatusEventType());
}
}
Thanks.. Regards
You can only manipulate UI elements, when your code is executed on the UI thread.
class EventHandler implements RfidEventsListener {
// Read Event Notification
public void eventReadNotify(RfidReadEvents e){
TagData[] myTags = myReader.Actions.getReadTags(100);
if (myTags != null)
{
for (int index = 0; index < myTags.length; index++)
{
System.out.println("Tag ID " + myTags[index].getTagID());
//I want to settext here
final String myText = myTags[index].getTagID();
runOnUiThread(new Runnable() {
#Override
public void run() {
myEditText.setText(myText);
}
});
}
}
}
// Status Event Notification
public void eventStatusNotify(RfidStatusEvents e) {
System.out.println("Status Notification: " +
e.StatusEventData.getStatusEventType());
}
}
This can be easily achieved by: (tested example)
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
/**
* This class was created by Anthony M Cannon on 16/05/2018.
*/
public class MainActivity extends AppCompatActivity {
private TextView textView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
EventHandler handler = new EventHandler();
handler.test();
}
class EventHandler {
void test() {
textView.setText("Hello, from EventHandler.");
}
}
}
When I run the command - cordova emulate android, I get the following error:
Application Error - net::ERR_FILE_NOT_FOUND (file:///android_asset/www/index.html)
CordovaActivity:
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova;
import java.util.ArrayList;
import java.util.Locale;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.AlertDialog;
import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
/**
* This class is the main Android activity that represents the Cordova
* application. It should be extended by the user to load the specific
* html file that contains the application.
*
* As an example:
*
* <pre>
* package org.apache.cordova.examples;
*
* import android.os.Bundle;
* import org.apache.cordova.*;
*
* public class Example extends CordovaActivity {
* #Override
* public void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
* super.init();
* // Load your application
* loadUrl(launchUrl);
* }
* }
* </pre>
*
* Cordova xml configuration: Cordova uses a configuration file at
* res/xml/config.xml to specify its settings. See "The config.xml File"
* guide in cordova-docs at http://cordova.apache.org/docs for the documentation
* for the configuration. The use of the set*Property() methods is
* deprecated in favor of the config.xml file.
*
*/
public class CordovaActivity extends Activity {
public static String TAG = "CordovaActivity";
// The webview for our app
protected CordovaWebView appView;
private static int ACTIVITY_STARTING = 0;
private static int ACTIVITY_RUNNING = 1;
private static int ACTIVITY_EXITING = 2;
// Keep app running when pause is received. (default = true)
// If true, then the JavaScript and native code continue to run in the background
// when another application (activity) is started.
protected boolean keepRunning = true;
// Flag to keep immersive mode if set to fullscreen
protected boolean immersiveMode;
// Read from config.xml:
protected CordovaPreferences preferences;
protected String launchUrl;
protected ArrayList<PluginEntry> pluginEntries;
protected CordovaInterfaceImpl cordovaInterface;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
LOG.i(TAG, "Apache Cordova native platform version " + CordovaWebView.CORDOVA_VERSION + " is starting");
LOG.d(TAG, "CordovaActivity.onCreate()");
// need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception
loadConfig();
if (!preferences.getBoolean("ShowTitle", false)) {
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
}
if (preferences.getBoolean("SetFullscreen", false)) {
Log.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.");
preferences.set("Fullscreen", true);
}
if (preferences.getBoolean("Fullscreen", false)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
immersiveMode = true;
} else {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
} else {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
super.onCreate(savedInstanceState);
cordovaInterface = makeCordovaInterface();
if (savedInstanceState != null) {
cordovaInterface.restoreInstanceState(savedInstanceState);
}
}
protected void init() {
appView = makeWebView();
createViews();
if (!appView.isInitialized()) {
appView.init(cordovaInterface, pluginEntries, preferences);
}
cordovaInterface.onCordovaInit(appView.getPluginManager());
// Wire the hardware volume controls to control media if desired.
String volumePref = preferences.getString("DefaultVolumeStream", "");
if ("media".equals(volumePref.toLowerCase(Locale.ENGLISH))) {
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
}
#SuppressWarnings("deprecation")
protected void loadConfig() {
ConfigXmlParser parser = new ConfigXmlParser();
parser.parse(this);
preferences = parser.getPreferences();
preferences.setPreferencesBundle(getIntent().getExtras());
launchUrl = parser.getLaunchUrl();
pluginEntries = parser.getPluginEntries();
Config.parser = parser;
}
//Suppressing warnings in AndroidStudio
#SuppressWarnings({"deprecation", "ResourceType"})
protected void createViews() {
//Why are we setting a constant as the ID? This should be investigated
appView.getView().setId(100);
appView.getView().setLayoutParams(new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
setContentView(appView.getView());
if (preferences.contains("BackgroundColor")) {
int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK);
// Background of activity:
appView.getView().setBackgroundColor(backgroundColor);
}
appView.getView().requestFocusFromTouch();
}
/**
* Construct the default web view object.
* <p/>
* Override this to customize the webview that is used.
*/
protected CordovaWebView makeWebView() {
return new CordovaWebViewImpl(makeWebViewEngine());
}
protected CordovaWebViewEngine makeWebViewEngine() {
return CordovaWebViewImpl.createEngine(this, preferences);
}
protected CordovaInterfaceImpl makeCordovaInterface() {
return new CordovaInterfaceImpl(this) {
#Override
public Object onMessage(String id, Object data) {
// Plumb this to CordovaActivity.onMessage for backwards compatibility
return CordovaActivity.this.onMessage(id, data);
}
};
}
/**
* Load the url into the webview.
*/
public void loadUrl(String url) {
if (appView == null) {
init();
}
// If keepRunning
this.keepRunning = preferences.getBoolean("KeepRunning", true);
appView.loadUrlIntoView(url, true);
}
/**
* Called when the system is about to start resuming a previous activity.
*/
#Override
protected void onPause() {
super.onPause();
LOG.d(TAG, "Paused the activity.");
if (this.appView != null) {
// CB-9382 If there is an activity that started for result and main activity is waiting for callback
// result, we shoudn't stop WebView Javascript timers, as activity for result might be using them
boolean keepRunning = this.keepRunning || this.cordovaInterface.activityResultCallback != null;
this.appView.handlePause(keepRunning);
}
}
/**
* Called when the activity receives a new intent
*/
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//Forward to plugins
if (this.appView != null)
this.appView.onNewIntent(intent);
}
/**
* Called when the activity will start interacting with the user.
*/
#Override
protected void onResume() {
super.onResume();
LOG.d(TAG, "Resumed the activity.");
if (this.appView == null) {
return;
}
// Force window to have focus, so application always
// receive user input. Workaround for some devices (Samsung Galaxy Note 3 at least)
this.getWindow().getDecorView().requestFocus();
this.appView.handleResume(this.keepRunning);
}
/**
* Called when the activity is no longer visible to the user.
*/
#Override
protected void onStop() {
super.onStop();
LOG.d(TAG, "Stopped the activity.");
if (this.appView == null) {
return;
}
this.appView.handleStop();
}
/**
* Called when the activity is becoming visible to the user.
*/
#Override
protected void onStart() {
super.onStart();
LOG.d(TAG, "Started the activity.");
if (this.appView == null) {
return;
}
this.appView.handleStart();
}
/**
* The final call you receive before your activity is destroyed.
*/
#Override
public void onDestroy() {
LOG.d(TAG, "CordovaActivity.onDestroy()");
super.onDestroy();
if (this.appView != null) {
appView.handleDestroy();
}
}
/**
* Called when view focus is changed
*/
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && immersiveMode) {
final int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
getWindow().getDecorView().setSystemUiVisibility(uiOptions);
}
}
#SuppressLint("NewApi")
#Override
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
// Capture requestCode here so that it is captured in the setActivityResultCallback() case.
cordovaInterface.setActivityResultRequestCode(requestCode);
super.startActivityForResult(intent, requestCode, options);
}
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* #param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* #param resultCode The integer result code returned by the child activity through its setResult().
* #param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
*/
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
LOG.d(TAG, "Incoming Result. Request code = " + requestCode);
super.onActivityResult(requestCode, resultCode, intent);
cordovaInterface.onActivityResult(requestCode, resultCode, intent);
}
/**
* Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
* The errorCode parameter corresponds to one of the ERROR_* constants.
*
* #param errorCode The error code corresponding to an ERROR_* value.
* #param description A String describing the error.
* #param failingUrl The url that failed to load.
*/
public void onReceivedError(final int errorCode, final String description, final String failingUrl) {
final CordovaActivity me = this;
// If errorUrl specified, then load it
final String errorUrl = preferences.getString("errorUrl", null);
if ((errorUrl != null) && (!failingUrl.equals(errorUrl)) && (appView != null)) {
// Load URL on UI thread
me.runOnUiThread(new Runnable() {
public void run() {
me.appView.showWebPage(errorUrl, false, true, null);
}
});
}
// If not, then display error dialog
else {
final boolean exit = !(errorCode == WebViewClient.ERROR_HOST_LOOKUP);
me.runOnUiThread(new Runnable() {
public void run() {
if (exit) {
me.appView.getView().setVisibility(View.GONE);
me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit);
}
}
});
}
}
/**
* Display an error dialog and optionally exit application.
*/
public void displayError(final String title, final String message, final String button, final boolean exit) {
final CordovaActivity me = this;
me.runOnUiThread(new Runnable() {
public void run() {
try {
AlertDialog.Builder dlg = new AlertDialog.Builder(me);
dlg.setMessage(message);
dlg.setTitle(title);
dlg.setCancelable(false);
dlg.setPositiveButton(button,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (exit) {
finish();
}
}
});
dlg.create();
dlg.show();
} catch (Exception e) {
finish();
}
}
});
}
/*
* Hook in Cordova for menu plugins
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (appView != null) {
appView.getPluginManager().postMessage("onCreateOptionsMenu", menu);
}
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (appView != null) {
appView.getPluginManager().postMessage("onPrepareOptionsMenu", menu);
}
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (appView != null) {
appView.getPluginManager().postMessage("onOptionsItemSelected", item);
}
return true;
}
/**
* Called when a message is sent to plugin.
*
* #param id The message id
* #param data The message data
* #return Object or null
*/
public Object onMessage(String id, Object data) {
if ("onReceivedError".equals(id)) {
JSONObject d = (JSONObject) data;
try {
this.onReceivedError(d.getInt("errorCode"), d.getString("description"), d.getString("url"));
} catch (JSONException e) {
e.printStackTrace();
}
} else if ("exit".equals(id)) {
finish();
}
return null;
}
protected void onSaveInstanceState(Bundle outState) {
cordovaInterface.onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
/**
* Called by the system when the device configuration changes while your activity is running.
*
* #param newConfig The new device configuration
*/
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (this.appView == null) {
return;
}
PluginManager pm = this.appView.getPluginManager();
if (pm != null) {
pm.onConfigurationChanged(newConfig);
}
}
/**
* Called by the system when the user grants permissions
*
* #param requestCode
* #param permissions
* #param grantResults
*/
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[],
int[] grantResults) {
try
{
cordovaInterface.onRequestPermissionResult(requestCode, permissions, grantResults);
}
catch (JSONException e)
{
LOG.d(TAG, "JSONException: Parameters fed into the method are not valid");
e.printStackTrace();
}
}
}
JS included:
<script type="text/javascript" src="cordova.js"></script>
<!-- build:js(.) scripts/vendor.js -->
<!-- bower:js -->
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
<script src="bower_components/angular-animate/angular-animate.js"></script>
<script src="bower_components/angular-cookies/angular-cookies.js"></script>
<script src="bower_components/angular-resource/angular-resource.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
<script src="bower_components/angular-touch/angular-touch.js"></script>
<!-- endbower -->
<!-- endbuild -->
<!-- build:js({.tmp,app}) scripts/scripts.js -->
<script src="scripts/app.js"></script>
<script src="scripts/controllers/main.js"></script>
<script src="scripts/controllers/scan.js"></script>
<script src="scripts/controllers/payment.js"></script>
<script src="scripts/services/cordova.js"></script>
<!-- endbuild -->
</body>
screenshot of the folder structure-
When I checked thoroughly, there is actually no index.html file generated. What might be the issue?
Cordova load HTML from assets to show UI, you must be missing some step in Apache Cordova CLI.
Since there is no html pages in Asset that's why cordova is unable to inflate any UI and showing that error.
What you can do
Try to create another project and follow instruction and try to execute commands in proper order.
once you have finished step 1 make sure there should be an auto generated index.html along with cordova.js in Asset folder like below :-
You can create assets/www folder and then add the HTML pages there. In this case, it is index.html.
You can follow this tutorial at
http://www.adobe.com/devnet/archive/html5/articles/getting-started-with-phonegap-in-eclipse-for-android.html
Create an assets/www directory and a libs directory inside of the new Android project. All of the HTML and JavaScript for your PhoneGap application interface will reside within the assets/www folder.
I'm searching for a while how to run my WebView forever. When the android function onPause() / onResume() is called. My WebView starts again.
I want the WebView to go on. Maybe the best to explane by an simple HTML example:
<html><head><title>Webview test Android</title></head>
<body>
<h1><div id="counter"></div></h1>
<script>
var counter = 0;
document.getElementById("counter").innerHTML = counter;
setTimeout(function(){ count(); }, 1000);
function count() {
counter++;
document.getElementById("counter").innerHTML = counter;
console.log("counter: " + counter);
setTimeout(function(){ count(); }, 1000);
}
</script>
</body>
</html>
What I want in the app behaviour is:
> Open the app
+ Html page starts counting
> Press the home button / multitask button
+ Html page is still counting (or doing other stuff)
> Get back to the app
+ Html page is still counting and dont reload.
First I uses my own code for WebView. But with a lot of android versions, I used a chromium-webview example from github
I looked into android WebView methods, but I cant figure a solution. I tried also mWebView.onPause(), mWebView.onResume()... With no results. Maybe someone can bring me in the right direction.
This is are the main functions:
private WebView mWebView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("main"," create ");
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.activity_main_webview);
mWebView.addJavascriptInterface(new NotificationBindObject(getApplicationContext()), "NotificationBind");
mWebView.getSettings().setDomStorageEnabled(true); // use localstorage
setUpWebViewDefaults(mWebView);
if (savedInstanceState != null) {
mWebView.restoreState(savedInstanceState);
}
if(mWebView.getUrl() == null) {
mWebView.loadUrl("file:///android_asset/www/index.html");
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the WebView state (including history stack)
mWebView.saveState(savedInstanceState);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
Update
Almost there... I made a Service that runs the WebView.
public class TestService extends Service {
private static WebView w;
private static MainActivity ma;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
public static void setMain(MainActivity a) {
ma = a;
Log.e("main", " setData " );
setView();
}
private static void setView() {
w = (WebView) ma.findViewById(R.id.webView);
Log.e("main", " setData ");
w.getSettings().setDomStorageEnabled(true); // use localstorage
w.getSettings().setJavaScriptEnabled(true);
//ma.setUpWebViewDefaults(w);
w.loadUrl("file:///android_asset/www/index.html");
}
}
MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("main"," create ");
if (savedInstanceState == null) {
setContentView(R.layout.activity_main);
Intent i = new Intent(MainActivity.this, TestService.class);
TestService.setMain(this);
MainActivity.this.startService(i);
} else {
...
}
...
}
Now when I see the console.log("counter" + counter); logging in Eclipse. The only problem is that the WebView in the layout is gone now when I'm back...
This is the code I have, I am trying to have multiple images slide across the screen. The specific error shows up for "ThisClass" in the "TimerTask thisTimerTask = new ThisClass();" line. I appreciate any feed back available
package your.package2.namespace2;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.view.Display;
import android.widget.Button;
import android.widget.ImageView;
#SuppressWarnings("unused")
public class ChangeuppicksActivity extends Activity {
Display thisDisplay;
ImageView img, img4, img5, img7;
Timer timer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
thisDisplay = getWindowManager().getDefaultDisplay();
TimerTask thisTimerTask = new ThisClass();
timer = new Timer();
timer.scheduleAtFixedRate(thisTimerTask, 1000, 16);
img = (ImageView) findViewById(R.id.pic1);
img4 = (ImageView) findViewById(R.id.pic4);
img5 = (ImageView) findViewById(R.id.pic5);
img7 = (ImageView) findViewById(R.id.pic7);
}
public void doSomething() {
int slideToPOS_X = (img.getLeft() - 7);
if (slideToPOS_X <= -img.getWidth()) {
int slideToPOS_X2 = (img4.getLeft() - 5);
if (slideToPOS_X2 <= -img4.getWidth()) {
slideToPOS_X2 = thisDisplay.getWidth();
}
img.layout(slideToPOS_X, 0, (slideToPOS_X + img.getWidth()), (0 + img.getHeight()));;
img4.layout(slideToPOS_X2, 0, (slideToPOS_X2 + img4.getWidth()), (0 + img4.getHeight()));
}
class ThisClass extends TimerTask {
#Override
public void run() {
ChangeuppicksActivity.this.runOnUiThread(new Runnable() {
public void run() {
doSomething();
}
});
}
}
}
}
Not sure if this is the root cause of your problem, but looks like you have one too many close brackets at the bottom of your class. Try removing one of the '}' at the bottom of the class to see if that makes your compiler any happier.
You are also missing a close bracket in your doSomething() method. I may have broken your logic, but try replacing the bottom with this:
public void doSomething() {
int slideToPOS_X = (img.getLeft() - 7);
if (slideToPOS_X <= -img.getWidth()) {
int slideToPOS_X2 = (img4.getLeft() - 5);
}
if (slideToPOS_X2 <= -img4.getWidth()) {
slideToPOS_X2 = thisDisplay.getWidth();
}
img.layout(slideToPOS_X, 0, (slideToPOS_X + img.getWidth()), (0 + img.getHeight()));;
img4.layout(slideToPOS_X2, 0, (slideToPOS_X2 + img4.getWidth()), (0 + img4.getHeight()));
}
class ThisClass extends TimerTask {
#Override
public void run() {
ChangeuppicksActivity.this.runOnUiThread(new Runnable() {
public void run() {
doSomething();
}
});
}
}
}
One of the close brackets at the end is superfluous and I think there should be an additional bracket closing the doSomething method. As it stands, ThisClass is defined inside the doSomething method - the second line of doSomething has an open bracket which isn't closed until the end of the class, which is hard to see as the code is not indented after the opening bracket.
Move ThisClass definition outside of the doSomething() method.